├── Tools
├── .gitignore
├── logs_to_manifest.py
└── package_release.ps1
├── .gitattributes
├── .idea
└── .idea.DrizzleEdit
│ └── .idea
│ ├── .name
│ ├── encodings.xml
│ ├── misc.xml
│ ├── vcs.xml
│ ├── indexLayout.xml
│ └── .gitignore
├── Drizzle.Logic.Tests
├── Usings.cs
├── LruCacheTest.cs
└── Drizzle.Logic.Tests.csproj
├── .gitmodules
├── LingoSource
├── inptBox.lingo
├── goback.lingo
├── massRenderLoop.lingo
├── stop.lingo
├── changeSize.lingo
├── cameraEditorStart.lingo
├── renderEffectsStart.lingo
├── testDrawLevel.lingo
├── getExtraTile.lingo
├── envEditorStart.lingo
├── renderPropsStart.lingo
├── exportAllBitmaps.lingo
├── sliderBehav.lingo
├── lightEditorStart.lingo
├── levelEditStart.lingo
├── loadLevelStart.lingo
├── massRenderStart.lingo
├── finished.lingo
├── renderLightStart2.lingo
├── envEditorLoop.lingo
├── LOstart.lingo
├── unify.lingo
├── levelEditor.lingo
├── globals.lingo
├── tileEditorStart.lingo
├── saveProject.lingo
├── effectsEditorStart.lingo
├── renderLight2.lingo
├── saveFile.lingo
└── propEditorStart.lingo
├── Drizzle.Editor
├── Assets
│ └── avalonia-logo.ico
├── FodyWeavers.xml
├── ViewModels
│ ├── Render
│ │ ├── RenderStageCompletedViewModel.cs
│ │ ├── RenderStageViewModelBase.cs
│ │ ├── RenderStageErrorViewModel.cs
│ │ ├── RenderStageLightViewModel.cs
│ │ ├── RenderStageLayersViewModel.cs
│ │ └── RenderStageEffectsViewModel.cs
│ ├── EditorTabs
│ │ ├── EditorTabViewModelBase.cs
│ │ ├── TabTileEditorViewModel.cs
│ │ ├── TabLevelOverviewViewModel.cs
│ │ └── TabGeometryEditorViewModel.cs
│ ├── ViewModelBase.cs
│ ├── MainEditorTabViewModel.cs
│ └── EditorContentViewModel.cs
├── Views
│ ├── LingoStatus.axaml.cs
│ ├── EditorContentView.axaml.cs
│ ├── EditorTabs
│ │ ├── TabTileEditorView.axaml.cs
│ │ ├── TabLevelOverviewView.axaml.cs
│ │ ├── TabGeometryEditorView.axaml.cs
│ │ ├── TabTileEditorView.axaml
│ │ └── TabLevelOverviewView.axaml
│ ├── Render
│ │ ├── RenderStageErrorView.axaml.cs
│ │ ├── RenderStageLayersView.axaml.cs
│ │ ├── RenderStageLightView.axaml.cs
│ │ ├── RenderStageCompletedView.axaml.cs
│ │ ├── RenderStageEffectsView.axaml.cs
│ │ ├── RenderStageCompletedView.axaml
│ │ ├── RenderStageErrorView.axaml
│ │ ├── RenderStageLightView.axaml
│ │ ├── RenderStageLayersView.axaml
│ │ ├── RenderWindow.axaml.cs
│ │ ├── RenderStageEffectsView.axaml
│ │ └── RenderWindow.axaml
│ ├── MainEditorTabView.axaml.cs
│ ├── MainEditorTabView.axaml
│ ├── LingoCastViewer.axaml.cs
│ ├── AboutWindow.axaml
│ ├── EditorContentView.axaml
│ ├── LingoStatus.axaml
│ ├── AboutWindow.axaml.cs
│ ├── MainWindow.axaml.cs
│ ├── LevelPreviewControl.cs
│ ├── EditorRendering.cs
│ └── LingoCastViewer.axaml
├── Helpers
│ ├── Swap.cs
│ ├── EnumBoolConverter.cs
│ ├── TrickHitTestOperation.cs
│ ├── Bresenham.cs
│ └── LingoImageAvaloniaHelper.cs
├── KeyMap.cs
├── App.axaml
├── ViewLocator.cs
├── Program.cs
├── FodyWeavers.xsd
├── Drizzle.Editor.csproj
├── App.axaml.cs
├── CommandLineArgs.cs
└── AvaloniaSeriLogger.cs
├── .vscode
└── extensions.json
├── Drizzle.Lingo.Runtime
├── Scripting
│ ├── CompiledScript.cs
│ ├── LingoScriptRuntime.cs
│ └── Binders.cs
├── Cast
│ ├── CastMember.Script.cs
│ ├── CastMember.Shape.cs
│ ├── CastMember.Text.cs
│ ├── CastMember.Bitmap.cs
│ └── CastMember.cs
├── Data
│ ├── ILingoListDuplicate.cs
│ ├── ILingoVector.cs
│ ├── LingoFormat.cs
│ ├── LingoSymbol.cs
│ ├── LingoPropertyList.cs
│ ├── LingoColor.cs
│ └── LingoPoint.cs
├── ISliceable.cs
├── LingoScriptRuntimeBase.cs
├── AssemblyInfo.cs
├── Xtra
│ ├── BaseXtra.cs
│ ├── ImgXtra.cs
│ └── FileIOXtra.cs
├── Parser
│ └── DebugPrint.cs
├── LingoGlobal.Mouse.cs
├── LingoGlobal.Random.cs
├── Utils
│ └── CultureFix.cs
├── Drizzle.Lingo.Runtime.csproj.DotSettings
├── LingoMask.cs
├── LingoGlobal.Key.cs
├── LingoGlobal.System.cs
├── Drizzle.Lingo.Runtime.csproj
├── LingoGlobal.Init.cs
├── Attributes.cs
├── LingoGlobal.Global.cs
├── Utility
│ └── ImageSharpExt.cs
├── LingoGlobal.Scripting.cs
├── LingoSprite.cs
├── LingoGlobal.Movie.cs
├── LingoRuntime.FileSystem.cs
├── lingo notes.md
├── LingoRuntime.Random.cs
├── LingoCastLib.cs
├── LingoRuntime.Clone.cs
└── LingoImage.Silhouette.cs
├── Drizzle.Lingo.Tests
├── Images
│ └── effectmask
│ │ ├── layer9.png
│ │ ├── dumpimage.png
│ │ └── flattenedgradientB.png
├── LingoNumberTest.cs
├── ParseTest.cs
├── Drizzle.Lingo.Tests.csproj
├── LingoImagePixelOpsTest.cs
├── LingoOperatorTest.cs
└── RngTest.cs
├── Drizzle.Ported
├── LingoParentScript.cs
├── LingoBehaviorScript.cs
├── AssemblyInfo.cs
├── Drizzle.Ported.csproj
├── MovieScript.cs
├── LingoScriptBase.cs
├── MovieScript.CacheLoadImage.cs
├── Constants.cs
└── LruCache.cs
├── .editorconfig
├── Directory.Build.props
├── .gitignore
├── Drizzle.Transpiler
└── Drizzle.Transpiler.csproj
├── Drizzle.Logic
├── Rendering
│ ├── RenderStage.cs
│ ├── RenderPreview.cs
│ ├── RenderStatus.cs
│ └── RenderCmd.cs
├── Drizzle.Logic.csproj
├── MathHelper.cs
├── ILingoRuntimeManager.cs
├── EditorRuntimeHelpers.cs
└── Vector2i.cs
├── Drizzle.Benchmarks
├── Program.cs
├── Drizzle.Benchmarks.csproj
└── ImageQuadCopy.cs
├── .github
└── workflows
│ ├── dotnet.yml
│ ├── render-all-levels.yml
│ └── publish-release.yml
├── Drizzle.ConsoleApp
└── Drizzle.ConsoleApp.csproj
├── LICENSE.txt
├── README.md
└── DrizzleEdit.sln.DotSettings
/Tools/.gitignore:
--------------------------------------------------------------------------------
1 | Logs/
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
--------------------------------------------------------------------------------
/.idea/.idea.DrizzleEdit/.idea/.name:
--------------------------------------------------------------------------------
1 | DrizzleEdit
--------------------------------------------------------------------------------
/Drizzle.Logic.Tests/Usings.cs:
--------------------------------------------------------------------------------
1 | global using NUnit.Framework;
2 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "Data"]
2 | path = Data
3 | url = https://github.com/PJB3005/Drizzle.Data.git
4 | branch = master
--------------------------------------------------------------------------------
/LingoSource/inptBox.lingo:
--------------------------------------------------------------------------------
1 |
2 | global levelName
3 |
4 | on change me
5 | levelName = sprite(me.spriteNum).text
6 | end
7 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Assets/avalonia-logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PJB3005/Drizzle/HEAD/Drizzle.Editor/Assets/avalonia-logo.ico
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-dotnettools.csharp",
4 | "editorconfig.editorconfig"
5 | ]
6 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Scripting/CompiledScript.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime.Scripting;
2 |
3 | public sealed class CompiledScript
4 | {
5 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Tests/Images/effectmask/layer9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PJB3005/Drizzle/HEAD/Drizzle.Lingo.Tests/Images/effectmask/layer9.png
--------------------------------------------------------------------------------
/Drizzle.Ported/LingoParentScript.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Ported;
2 |
3 | public abstract class LingoParentScript : LingoScriptBase
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Cast/CastMember.Script.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime.Cast;
2 |
3 | public sealed partial class CastMember
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Tests/Images/effectmask/dumpimage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PJB3005/Drizzle/HEAD/Drizzle.Lingo.Tests/Images/effectmask/dumpimage.png
--------------------------------------------------------------------------------
/Drizzle.Lingo.Tests/Images/effectmask/flattenedgradientB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PJB3005/Drizzle/HEAD/Drizzle.Lingo.Tests/Images/effectmask/flattenedgradientB.png
--------------------------------------------------------------------------------
/Drizzle.Editor/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Drizzle.Ported/LingoBehaviorScript.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Ported;
2 |
3 | public class LingoBehaviorScript : LingoScriptBase
4 | {
5 | public int spritenum { get; set; }
6 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Data/ILingoListDuplicate.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime;
2 |
3 | public interface ILingoListDuplicate
4 | {
5 | ILingoListDuplicate duplicate();
6 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/ISliceable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Drizzle.Lingo.Runtime;
4 |
5 | public interface ISliceable
6 | {
7 | public object this[Range idx] { get; }
8 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Data/ILingoVector.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime;
2 |
3 | public interface ILingoVector
4 | {
5 | int CountElems { get; }
6 | object? this[int index] { get; }
7 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/Render/RenderStageCompletedViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Editor.ViewModels.Render;
2 |
3 | public sealed class RenderStageCompletedViewModel : RenderStageViewModelBase
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoScriptRuntimeBase.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime;
2 |
3 | public abstract class LingoScriptRuntimeBase
4 | {
5 | public abstract void Init(object movieScript, LingoGlobal global);
6 | }
--------------------------------------------------------------------------------
/Drizzle.Ported/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | // WHEE I throw the magic performance word and hope my code is blessed to go ever so slightly faster.
4 | [module: SkipLocalsInit]
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/.idea.DrizzleEdit/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/EditorTabs/EditorTabViewModelBase.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Editor.ViewModels.EditorTabs;
2 |
3 | public abstract class EditorTabViewModelBase : ViewModelBase
4 | {
5 | public abstract string Title { get; }
6 | }
--------------------------------------------------------------------------------
/LingoSource/goback.lingo:
--------------------------------------------------------------------------------
1 | on exitFrame me
2 | -- member("dpImage").image = image()
3 | global gMassRenderL
4 |
5 | if gMassRenderL = [] then
6 | _movie.go(9)
7 | else
8 | _movie.go(90)
9 | end if
10 |
11 | end
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/EditorTabs/TabTileEditorViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Editor.ViewModels.EditorTabs;
2 |
3 | public sealed class TabTileEditorViewModel : EditorTabViewModelBase
4 | {
5 | public override string Title => "Tiles";
6 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/ViewModelBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using ReactiveUI;
5 |
6 | namespace Drizzle.Editor.ViewModels;
7 |
8 | public class ViewModelBase : ReactiveObject
9 | {
10 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | // WHEE I throw the magic performance word and hope my code is blessed to go ever so slightly faster.
4 | [module: SkipLocalsInit]
5 | [assembly: InternalsVisibleTo("Drizzle.Lingo.Tests")]
6 |
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/Render/RenderStageViewModelBase.cs:
--------------------------------------------------------------------------------
1 | using Drizzle.Logic;
2 |
3 | namespace Drizzle.Editor.ViewModels.Render;
4 |
5 | public abstract class RenderStageViewModelBase : ViewModelBase
6 | {
7 | public virtual (int max, int current)? Progress => default;
8 | }
--------------------------------------------------------------------------------
/.idea/.idea.DrizzleEdit/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.idea.DrizzleEdit/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 |
6 | [*.cs]
7 | indent_size = 4
8 | indent_style = space
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
12 | [*.lingo]
13 | indent_size = 2
14 | indent_style = space
15 |
16 | [*.md]
17 | indent_size = 2
18 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/LingoStatus.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Markup.Xaml;
3 |
4 | namespace Drizzle.Editor.Views;
5 |
6 | public sealed partial class LingoStatus : UserControl
7 | {
8 | public LingoStatus()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/EditorContentView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Markup.Xaml;
3 |
4 | namespace Drizzle.Editor.Views;
5 |
6 | public sealed partial class EditorContentView : UserControl
7 | {
8 | public EditorContentView()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/.idea/.idea.DrizzleEdit/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | LingoSource
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | 0.1.7.2
4 | $(DefineConstants);FULL_RELEASE
5 | net7.0
6 | 11
7 |
8 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/EditorTabs/TabTileEditorView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Markup.Xaml;
3 |
4 | namespace Drizzle.Editor.Views.EditorTabs;
5 |
6 | public partial class TabTileEditorView : UserControl
7 | {
8 | public TabTileEditorView()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Data/LingoFormat.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime;
2 |
3 | public static class LingoFormat
4 | {
5 | public static string LingoToString(object? obj)
6 | {
7 | if (obj is string str)
8 | return $"\"{str}\"";
9 |
10 | return obj?.ToString() ?? "";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.suo
2 | *.user
3 | .vs/
4 | [Bb]in/
5 | [Oo]bj/
6 | _UpgradeReport_Files/
7 | [Pp]ackages/
8 |
9 | Thumbs.db
10 | Desktop.ini
11 | .DS_Store
12 | .desktop
13 | /Drizzle.Ported/Translated
14 |
15 | # Temporary directory used when making release builds.
16 | ReleaseBuild/
17 | # Directory containing release builds.
18 | Release/
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/Render/RenderStageErrorView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Markup.Xaml;
3 |
4 | namespace Drizzle.Editor.Views.Render;
5 |
6 | public partial class RenderStageErrorView : UserControl
7 | {
8 | public RenderStageErrorView()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/Render/RenderStageLayersView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Markup.Xaml;
3 |
4 | namespace Drizzle.Editor.Views.Render;
5 |
6 | public partial class RenderStageLayersView : UserControl
7 | {
8 | public RenderStageLayersView()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/Render/RenderStageLightView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Markup.Xaml;
3 |
4 | namespace Drizzle.Editor.Views.Render;
5 |
6 | public partial class RenderStageLightView : UserControl
7 | {
8 | public RenderStageLightView()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Xtra/BaseXtra.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime.Xtra;
2 |
3 | public abstract class BaseXtra
4 | {
5 | public abstract BaseXtra Duplicate();
6 |
7 | // Editor does a pattern where it does xtra().new(), work around this.
8 | public dynamic @new()
9 | {
10 | return Duplicate();
11 | }
12 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/EditorTabs/TabLevelOverviewView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Markup.Xaml;
3 |
4 | namespace Drizzle.Editor.Views.EditorTabs;
5 |
6 | public partial class TabLevelOverviewView : UserControl
7 | {
8 | public TabLevelOverviewView()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/EditorTabs/TabGeometryEditorView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Markup.Xaml;
3 |
4 | namespace Drizzle.Editor.Views.EditorTabs;
5 |
6 | public partial class TabGeometryEditorView : UserControl
7 | {
8 | public TabGeometryEditorView()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/Render/RenderStageCompletedView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Markup.Xaml;
3 |
4 | namespace Drizzle.Editor.Views.Render;
5 |
6 | public partial class RenderStageCompletedView : UserControl
7 | {
8 | public RenderStageCompletedView()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Drizzle.Transpiler/Drizzle.Transpiler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | enable
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Drizzle.Logic/Rendering/RenderStage.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Logic.Rendering;
2 |
3 | public enum RenderStage
4 | {
5 | Start,
6 | CameraSetup,
7 | RenderLayers,
8 | RenderPropsPreEffects,
9 | RenderEffects,
10 | RenderPropsPostEffects,
11 | RenderLight,
12 | Finalize,
13 | RenderColors,
14 | Finished,
15 | SaveFile,
16 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Parser/DebugPrint.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace Drizzle.Lingo.Runtime.Parser;
4 |
5 | public static class DebugPrint
6 | {
7 | public static string PrintAstNode(AstNode.Base node)
8 | {
9 | var sb = new StringBuilder();
10 |
11 | node.DebugPrint(sb, 0);
12 |
13 | return sb.ToString();
14 | }
15 | }
--------------------------------------------------------------------------------
/.idea/.idea.DrizzleEdit/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /contentModel.xml
6 | /projectSettingsUpdater.xml
7 | /.idea.DrizzleEdit.iml
8 | /modules.xml
9 | # Datasource local storage ignored files
10 | /dataSources/
11 | /dataSources.local.xml
12 | # Editor-based HTTP Client requests
13 | /httpRequests/
14 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/MainEditorTabView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Markup.Xaml;
3 | using JetBrains.Annotations;
4 |
5 | namespace Drizzle.Editor.Views;
6 |
7 | [UsedImplicitly]
8 | public sealed partial class MainEditorTabView : UserControl
9 | {
10 | public MainEditorTabView()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/Render/RenderStageErrorViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Drizzle.Editor.ViewModels.Render;
4 |
5 | public sealed class RenderStageErrorViewModel : RenderStageViewModelBase
6 | {
7 | public string ExceptionMessage { get; }
8 |
9 | public RenderStageErrorViewModel(Exception exception)
10 | {
11 | ExceptionMessage = exception.ToString();
12 | }
13 | }
--------------------------------------------------------------------------------
/Drizzle.Logic/Drizzle.Logic.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | enable
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoGlobal.Mouse.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime;
2 |
3 | public sealed partial class LingoGlobal
4 | {
5 | public Mouse _mouse { get; private set; } = default!;
6 |
7 | public sealed class Mouse
8 | {
9 | public LingoPoint mouseloc => default;
10 | public LingoNumber mousedown => 0;
11 | public LingoNumber rightmousedown => 0;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/LingoSource/massRenderLoop.lingo:
--------------------------------------------------------------------------------
1 | global gMassRenderL, gViewRender
2 |
3 | on exitFrame me
4 | gMassRenderL.deleteAt(1)
5 |
6 | if gMassRenderL.count = 0 then
7 | alert("Mass Render Finished")
8 | _movie.go(1)
9 | else
10 | put "started rendering:" && gMassRenderL[1]
11 | script("loadLevel").loadLevel(gMassRenderL[1], 1)
12 | gViewRender = 0
13 | _movie.go(42)
14 | end if
15 | end
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/EditorTabs/TabLevelOverviewViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Editor.ViewModels.EditorTabs;
2 |
3 | public sealed class TabLevelOverviewViewModel : EditorTabViewModelBase
4 | {
5 | public EditorContentViewModel ParentVm { get; }
6 | public override string Title => "Overview";
7 |
8 | public TabLevelOverviewViewModel(EditorContentViewModel parentVm)
9 | {
10 | ParentVm = parentVm;
11 | }
12 | }
--------------------------------------------------------------------------------
/Drizzle.Ported/Drizzle.Ported.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | CS8981
4 | true
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoGlobal.Random.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime;
2 |
3 | public sealed partial class LingoGlobal
4 | {
5 | public LingoNumber the_randomSeed
6 | {
7 | get => (int) LingoRuntime.RngSeed;
8 | set => LingoRuntime.RngSeed = (uint) value.IntValue;
9 | }
10 |
11 | public LingoNumber random(LingoNumber max)
12 | {
13 | return LingoRuntime.Random(max.IntValue);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Drizzle.Logic/MathHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Logic;
2 |
3 | public static class MathHelper
4 | {
5 | public static void SatAdd(ref byte val, byte add)
6 | {
7 | val = SatAdd(val, add);
8 | }
9 |
10 | public static byte SatAdd(byte val, byte add)
11 | {
12 | var added = val + add;
13 | if (added > byte.MaxValue)
14 | return byte.MaxValue;
15 |
16 | return (byte)added;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Utils/CultureFix.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Threading;
3 |
4 | namespace Drizzle.Lingo.Runtime.Utils;
5 |
6 | public static class CultureFix
7 | {
8 | public static void FixCulture()
9 | {
10 | var enUs = CultureInfo.GetCultureInfoByIetfLanguageTag("en-US");
11 | CultureInfo.DefaultThreadCurrentCulture = enUs;
12 | CultureInfo.DefaultThreadCurrentUICulture = enUs;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Helpers/Swap.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Drizzle.Editor.Helpers;
4 |
5 | public static class Swap
6 | {
7 | ///
8 | /// Swap and if necessary, so that <= .
9 | ///
10 | public static void Asc(ref T a, ref T b) where T : IComparable
11 | {
12 | if (a.CompareTo(b) > 0)
13 | (a, b) = (b, a);
14 | }
15 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/MainEditorTabView.axaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LingoSource/stop.lingo:
--------------------------------------------------------------------------------
1 | global gSaveProps
2 |
3 | on stopMovie me
4 | -- repeat with q = 1 to 2000 then
5 | -- (member q of castLib 2).erase()
6 | -- end repeat
7 |
8 | -- wdth = baScreenInfo("width")
9 | -- if wdth <> gSaveProps[1] then
10 | -- changeBack = baSetDisplay(gSaveProps[1], gSaveProps[2], gSaveProps[3], "perm", FALSE)
11 | -- end if
12 |
13 | changeBack = baSetDisplay(gSaveProps[1], gSaveProps[2], gSaveProps[3], "perm", FALSE)
14 | end
15 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Drizzle.Lingo.Runtime.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
--------------------------------------------------------------------------------
/Drizzle.Ported/MovieScript.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Drizzle.Lingo.Runtime;
3 |
4 | namespace Drizzle.Ported;
5 |
6 | [MovieScript]
7 | public sealed partial class MovieScript : LingoScriptBase
8 | {
9 | public void Init(LingoGlobal global)
10 | {
11 | Init(this, global);
12 | }
13 | }
14 |
15 | public static class MovieScriptExt
16 | {
17 | public static MovieScript MovieScript(this LingoRuntime runtime) => (MovieScript)runtime.MovieScriptInstance;
18 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/KeyMap.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Avalonia.Input;
3 |
4 | namespace Drizzle.Editor;
5 |
6 | ///
7 | /// Avalonia -> Lingo key map.
8 | ///
9 | public static class KeyMap
10 | {
11 | public static readonly Dictionary Map = new()
12 | {
13 | { Key.Return, 36 },
14 | { Key.Up, 126 },
15 | { Key.Down, 125 },
16 | { Key.Left, 123 },
17 | { Key.Right, 124 },
18 | };
19 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoMask.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime;
2 |
3 | public sealed class LingoMask
4 | {
5 | // Currently 1-bit masks are assumed, higher-bit transparency masks not supported.
6 |
7 | public int Width { get; }
8 | public int Height { get; }
9 | public byte[] Data { get; }
10 |
11 | public LingoMask(int width, int height, byte[] data)
12 | {
13 | Width = width;
14 | Height = height;
15 | Data = data;
16 | }
17 | }
--------------------------------------------------------------------------------
/Drizzle.Benchmarks/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Reflection;
3 | using BenchmarkDotNet.Running;
4 | using Drizzle.Benchmarks;
5 |
6 | var benchmark = new ImageQuadCopy();
7 | benchmark.Setup();
8 |
9 | for (var i = 0; i < 10; i++)
10 | {
11 | benchmark.Bench();
12 | }
13 |
14 | var sw = new Stopwatch();
15 | for (var i = 0; i < 30; i++)
16 | {
17 | sw.Restart();
18 | benchmark.Bench();
19 | sw.Stop();
20 | Console.WriteLine(sw.Elapsed);
21 | }
22 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/Render/RenderStageEffectsView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Controls.Templates;
3 | using Avalonia.Layout;
4 | using Avalonia.Markup.Xaml;
5 | using Avalonia.Markup.Xaml.Templates;
6 | using Drizzle.Editor.ViewModels.Render;
7 |
8 | namespace Drizzle.Editor.Views.Render;
9 |
10 | public partial class RenderStageEffectsView : UserControl
11 | {
12 | public RenderStageEffectsView()
13 | {
14 | InitializeComponent();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Tests/LingoNumberTest.cs:
--------------------------------------------------------------------------------
1 | using Drizzle.Lingo.Runtime;
2 | using NUnit.Framework;
3 |
4 | namespace Drizzle.Lingo.Tests;
5 |
6 | [TestFixture]
7 | [Parallelizable(ParallelScope.All)]
8 | public sealed class LingoNumberTest
9 | {
10 | [Test]
11 | [TestCase("2", ExpectedResult = "1")]
12 | [TestCase("2.0", ExpectedResult = "1.4142")]
13 | public string TestSqrt(string num)
14 | {
15 | return LingoNumber.Sqrt(LingoNumber.Parse(num)).ToString();
16 | }
17 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Cast/CastMember.Shape.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime.Cast;
2 |
3 | public sealed partial class CastMember
4 | {
5 | public LingoNumber _lineDirection;
6 |
7 | public LingoNumber linedirection
8 | {
9 | get
10 | {
11 | AssertType(CastMemberType.Shape);
12 | return _lineDirection;
13 | }
14 | set
15 | {
16 | AssertType(CastMemberType.Shape);
17 | _lineDirection = value;
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/EditorTabs/TabTileEditorView.axaml:
--------------------------------------------------------------------------------
1 |
7 | tile editor idk
8 |
9 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoGlobal.Key.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Serilog;
3 |
4 | namespace Drizzle.Lingo.Runtime;
5 |
6 | public sealed partial class LingoGlobal
7 | {
8 | public Key _key { get; private set; } = default!;
9 |
10 | public sealed class Key
11 | {
12 | public LingoNumber keypressed(object keyName)
13 | {
14 | return 0;
15 | }
16 |
17 | public LingoNumber keypressed(int keyCode)
18 | {
19 | return 0;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/Render/RenderStageLightViewModel.cs:
--------------------------------------------------------------------------------
1 | using Drizzle.Logic;
2 | using Drizzle.Logic.Rendering;
3 |
4 | namespace Drizzle.Editor.ViewModels.Render;
5 |
6 | public class RenderStageLightViewModel : RenderStageViewModelBase
7 | {
8 | public int CurrentLayer { get; }
9 | public override (int max, int current)? Progress { get; }
10 |
11 | public RenderStageLightViewModel(RenderStageStatusLight status)
12 | {
13 | CurrentLayer = status.CurrentLayer;
14 | Progress = (30, status.CurrentLayer);
15 | }
16 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoGlobal.System.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Drizzle.Lingo.Runtime;
4 |
5 | public sealed partial class LingoGlobal
6 | {
7 | public System _system { get; private set; } = default!;
8 |
9 | public sealed class System
10 | {
11 | private readonly LingoGlobal _global;
12 |
13 | public System(LingoGlobal global)
14 | {
15 | _global = global;
16 | }
17 |
18 | public LingoNumber milliseconds => (int)_global.LingoRuntime.Stopwatch.ElapsedMilliseconds;
19 | }
20 | }
--------------------------------------------------------------------------------
/Drizzle.Logic.Tests/LruCacheTest.cs:
--------------------------------------------------------------------------------
1 | using Drizzle.Ported;
2 |
3 | namespace Drizzle.Logic.Tests;
4 |
5 | [TestFixture]
6 | [Parallelizable(ParallelScope.All)]
7 | [TestOf(typeof(LruCache<,>))]
8 | public sealed class LruCacheTest
9 | {
10 | [Test]
11 | public void Test()
12 | {
13 | var cache = new LruCache(2);
14 | cache.Get(1, Load);
15 | cache.Get(2, Load);
16 | cache.Get(1, Load);
17 | cache.Get(3, Load);
18 |
19 | static string Load(int key) => key.ToString();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/Render/RenderStageLayersViewModel.cs:
--------------------------------------------------------------------------------
1 | using Drizzle.Logic;
2 | using Drizzle.Logic.Rendering;
3 |
4 | namespace Drizzle.Editor.ViewModels.Render;
5 |
6 | public sealed class RenderStageLayersViewModel : RenderStageViewModelBase
7 | {
8 | public override (int max, int current)? Progress { get; }
9 |
10 | public int CurrentLayer { get; }
11 |
12 | public RenderStageLayersViewModel(RenderStageStatusLayers status)
13 | {
14 | CurrentLayer = status.CurrentLayer;
15 | Progress = (3, 3 - status.CurrentLayer);
16 | }
17 | }
--------------------------------------------------------------------------------
/Drizzle.Ported/LingoScriptBase.cs:
--------------------------------------------------------------------------------
1 | using Drizzle.Lingo.Runtime;
2 |
3 | namespace Drizzle.Ported;
4 |
5 | public abstract class LingoScriptBase : LingoScriptRuntimeBase
6 | {
7 | protected MovieScript _movieScript;
8 | protected LingoGlobal _global;
9 |
10 | public void Init(MovieScript movieScript, LingoGlobal global)
11 | {
12 | _movieScript = movieScript;
13 | _global = global;
14 | }
15 |
16 | public sealed override void Init(object movieScript, LingoGlobal global)
17 | {
18 | Init((MovieScript) movieScript, global);
19 | }
20 | }
--------------------------------------------------------------------------------
/LingoSource/changeSize.lingo:
--------------------------------------------------------------------------------
1 |
2 | global gLOProps, newSize, extraBufferTiles, gLEprops
3 | on exitFrame me
4 | if _key.keyPressed("A") and _movie.window.sizeState <> #minimized then
5 | if (gLOprops.size <> point(newSize[1], newSize[2]))or(newSize[3]>0)or(newSize[4]>0) then
6 | resizeLevel(point(newSize[1], newSize[2]),newSize[3],newSize[4] )
7 | end if
8 | gLOProps.extraTiles = extraBufferTiles.duplicate()
9 | _movie.go(9)
10 | else if _key.keyPressed("C") and _movie.window.sizeState <> #minimized then
11 | _movie.go(9)
12 | else
13 | go the frame
14 | end if
15 | end
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Xtra/ImgXtra.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using SixLabors.ImageSharp;
3 |
4 | namespace Drizzle.Lingo.Runtime.Xtra;
5 |
6 | public sealed class ImgXtra : BaseXtra
7 | {
8 | public override BaseXtra Duplicate()
9 | {
10 | return new ImgXtra();
11 | }
12 |
13 | public int ix_saveimage(LingoPropertyList props)
14 | {
15 | var img = (LingoImage)props["image"]!;
16 | var fileName = (string)props["filename"]!;
17 |
18 | using var file = File.Create(fileName);
19 | img.SaveAsPng(file);
20 |
21 | return 1;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Drizzle.Logic/Rendering/RenderPreview.cs:
--------------------------------------------------------------------------------
1 | using Drizzle.Lingo.Runtime;
2 |
3 | namespace Drizzle.Logic.Rendering;
4 |
5 | ///
6 | /// Represents the necessary state to render a preview for the editor window.
7 | ///
8 | public abstract record RenderPreview;
9 |
10 | public sealed record RenderPreviewEffects(
11 | LingoImage[] Layers,
12 | LingoImage BlackOut1,
13 | LingoImage BlackOut2) :
14 | RenderPreview;
15 |
16 | public sealed record RenderPreviewProps(LingoImage[] Layers) : RenderPreview;
17 | public sealed record RenderPreviewLights(LingoImage[] Layers) : RenderPreview;
18 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Drizzle.Lingo.Runtime.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | enable
5 | true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoGlobal.Init.cs:
--------------------------------------------------------------------------------
1 | using Drizzle.Lingo.Runtime.Scripting;
2 |
3 | namespace Drizzle.Lingo.Runtime;
4 |
5 | public sealed partial class LingoGlobal
6 | {
7 | public LingoRuntime LingoRuntime { get; }
8 |
9 | public LingoGlobal(LingoRuntime lingoRuntime)
10 | {
11 | LingoRuntime = lingoRuntime;
12 | }
13 |
14 | public void Init()
15 | {
16 | _system = new System(this);
17 | _key = new Key();
18 | _mouse = new Mouse();
19 | _movie = new Movie(this);
20 | _global = new Global(this);
21 | ScriptRuntime = new LingoScriptRuntime(this);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Drizzle.Editor/App.axaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/LingoSource/cameraEditorStart.lingo:
--------------------------------------------------------------------------------
1 |
2 | global gCameraProps, gLOprops, gLeProps
3 |
4 | on exitFrame me
5 |
6 |
7 |
8 | cols: number = gLOprops.size.loch
9 | rows: number = gLOprops.size.locv
10 |
11 | -- member("TEimg1").image = image(cols*16, rows*16, 16)
12 | -- member("TEimg2").image = image(cols*16, rows*16, 16)
13 | -- member("TEimg3").image = image(cols*16, rows*16, 16)
14 |
15 | member("levelEditImageShortCuts").image = image(cols*5, rows*5, 1)
16 | drawShortCutsImg(rect(1,1,cols,rows), 5, 1)
17 |
18 | repeat with q = 1 to 3 then
19 | miniLvlEditDraw(q)
20 | end repeat
21 |
22 | script("cameraEditor").drawAll()
23 | end
--------------------------------------------------------------------------------
/Drizzle.Editor/Helpers/EnumBoolConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using Avalonia.Data;
4 | using Avalonia.Data.Converters;
5 |
6 | namespace Drizzle.Editor.Helpers;
7 |
8 | public sealed class EnumBoolConverter : IValueConverter
9 | {
10 | public static EnumBoolConverter Instance { get; } = new();
11 |
12 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
13 | {
14 | return value?.Equals(parameter) ?? false;
15 | }
16 |
17 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
18 | {
19 | return value?.Equals(true) == true ? parameter : BindingOperations.DoNothing;
20 | }
21 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/LingoCastViewer.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia;
3 | using Avalonia.Controls;
4 | using Avalonia.Markup.Xaml;
5 | using Drizzle.Editor.ViewModels;
6 |
7 | namespace Drizzle.Editor.Views;
8 |
9 | public sealed partial class LingoCastViewer : Window
10 | {
11 | public LingoCastViewer()
12 | {
13 | InitializeComponent();
14 | #if DEBUG
15 | this.AttachDevTools();
16 | #endif
17 | }
18 |
19 | private void OnClosed(object? sender, EventArgs e)
20 | {
21 | (DataContext as LingoCastViewerViewModel)?.Closed();
22 | }
23 |
24 | private void OpOpened(object? sender, EventArgs e)
25 | {
26 | (DataContext as LingoCastViewerViewModel)?.Opened();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Attributes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Drizzle.Lingo.Runtime;
4 |
5 | [AttributeUsage(AttributeTargets.Class, Inherited = false)]
6 | public sealed class MovieScriptAttribute : Attribute
7 | {
8 | }
9 |
10 | [AttributeUsage(AttributeTargets.Class, Inherited = false)]
11 | public sealed class ParentScriptAttribute : Attribute
12 | {
13 | }
14 |
15 | [AttributeUsage(AttributeTargets.Class, Inherited = false)]
16 | public sealed class BehaviorScriptAttribute : Attribute
17 | {
18 | }
19 |
20 | [AttributeUsage(AttributeTargets.Field)]
21 | public sealed class LingoGlobalAttribute : Attribute
22 | {
23 | }
24 |
25 | [AttributeUsage(AttributeTargets.Field)]
26 | public sealed class LingoPropertyAttribute : Attribute
27 | {
28 | }
--------------------------------------------------------------------------------
/LingoSource/renderEffectsStart.lingo:
--------------------------------------------------------------------------------
1 | global vertRepeater, r, gLEprops, gEEprops, gTEprops, gTiles, keepLooping, gLOprops
2 |
3 | on exitFrame me
4 | type tm: number
5 | type val: number
6 |
7 |
8 | tm = _system.milliseconds
9 |
10 | repeat with q = 0 to 29 then
11 | sprite(50-q).loc = point((1024/2)-q, (768/2)-q)
12 | val = (q.float+1.0)/30.0
13 | -- put val
14 | sprite(50-q).color = color(val*255, val*255, val*255)
15 | end repeat
16 |
17 | sprite(57).visibility = 0
18 | sprite(58).visibility = 0
19 |
20 | vertRepeater = 100000
21 |
22 |
23 |
24 |
25 | if gEEprops.effects.count > 0 then
26 | r = 0
27 | keepLooping = 1
28 | else
29 | go(56)
30 | end if
31 | end
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Drizzle.Ported/MovieScript.CacheLoadImage.cs:
--------------------------------------------------------------------------------
1 | using Drizzle.Lingo.Runtime;
2 |
3 | namespace Drizzle.Ported;
4 |
5 | public sealed partial class MovieScript
6 | {
7 | private readonly LruCache _imageCache = new(64);
8 |
9 | public LingoImage cacheloadimage(string fileName)
10 | {
11 | return _imageCache.Get(fileName, this, static (state, fileName) => state.CacheLoadImageLoad(fileName));
12 | }
13 |
14 | private LingoImage CacheLoadImageLoad(string fileName)
15 | {
16 | var member = _global.member("previewImprt")!;
17 | member.importfileinto(fileName);
18 | member.name = "previewImprt";
19 | return member.image!;
20 | }
21 |
22 | public void ImageCacheClear() => _imageCache.Clear();
23 | }
24 |
--------------------------------------------------------------------------------
/Drizzle.Logic/ILingoRuntimeManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Drizzle.Lingo.Runtime;
4 |
5 | namespace Drizzle.Logic;
6 |
7 | ///
8 | /// Represents an "owner" of an isolated Lingo runtime.
9 | /// Provides some thread-safe APIs for stuff like cast inspection.
10 | ///
11 | ///
12 | /// At least, thread-safe from the main thread.
13 | ///
14 | public interface ILingoRuntimeManager
15 | {
16 | ///
17 | /// Executes an action on the thread of the lingo runtime.
18 | ///
19 | Task Exec(Action action);
20 |
21 | ///
22 | /// Executes an action on the thread of the lingo runtime.
23 | ///
24 | Task Exec(Func func);
25 | }
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: build & test
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | with:
17 | submodules: true
18 | - name: Setup .NET
19 | uses: actions/setup-dotnet@v1
20 | with:
21 | dotnet-version: 7.0.x
22 | - name: Restore dependencies
23 | run: dotnet restore
24 | - name: Run transpiler
25 | run: dotnet run --project Drizzle.Transpiler/Drizzle.Transpiler.csproj -- LingoSource Drizzle.Ported/Translated
26 | - name: Build
27 | run: dotnet build --no-restore
28 | - name: Test
29 | run: dotnet test --no-build --verbosity normal
30 |
--------------------------------------------------------------------------------
/LingoSource/testDrawLevel.lingo:
--------------------------------------------------------------------------------
1 | global gSkyColor, lightRects, gFullRender
2 | on exitFrame me
3 | gFullRender = 0
4 | lightRects = [rect(0,0,0,0), rect(0,0,0,0)]
5 | drawTestLevel()
6 | member("finalfg").image.setPixel(0, 0, gSkyColor)--skyColor
7 | member("finalfg").image.setPixel(1, 0, gSkyColor)--fogColor
8 | member("finalfg").image.setPixel(2, 0, color(10,10,10))--blackColor
9 | member("finalfg").image.setPixel(3, 0, color(10,10,10))--itemcolorColor
10 |
11 | member("finalfg").image.setPixel(0, 1, color(10,10,10))
12 | member("finalfg").image.setPixel(1, 1, color(10,10,10))
13 | global gLoadedName, levelName
14 | levelName = gLoadedName
15 | member("TextInput").text = gLoadedName
16 |
17 | put "I'M DOING A TEST RENDER!"
18 | alert("I'M DOING A TEST RENDER!")
19 |
20 | go(76)
21 | end
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewLocator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia.Controls;
3 | using Avalonia.Controls.Templates;
4 | using Drizzle.Editor.ViewModels;
5 |
6 | namespace Drizzle.Editor;
7 |
8 | public class ViewLocator : IDataTemplate
9 | {
10 | public bool SupportsRecycling => false;
11 |
12 | public IControl Build(object data)
13 | {
14 | var name = data.GetType().FullName!.Replace("ViewModel", "View");
15 | var type = Type.GetType(name);
16 |
17 | if (type != null)
18 | {
19 | return (Control)Activator.CreateInstance(type)!;
20 | }
21 | else
22 | {
23 | return new TextBlock { Text = "Not Found: " + name };
24 | }
25 | }
26 |
27 | public bool Match(object data)
28 | {
29 | return data is ViewModelBase;
30 | }
31 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/AboutWindow.axaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Drizzle.ConsoleApp/Drizzle.ConsoleApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | enable
6 | true
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoGlobal.Global.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Serilog;
3 |
4 | namespace Drizzle.Lingo.Runtime;
5 |
6 | public sealed partial class LingoGlobal
7 | {
8 | public Global _global { get; private set; } = default!;
9 |
10 | public sealed class Global
11 | {
12 | private readonly LingoGlobal _global;
13 |
14 | public Global(LingoGlobal global)
15 | {
16 | _global = global;
17 | }
18 |
19 | public void clearglobals()
20 | {
21 | Log.Debug("Clearing globals");
22 | var movieScript = _global.MovieScriptInstance;
23 | foreach (var field in movieScript.GetType().GetFields())
24 | {
25 | if (Attribute.IsDefined(field, typeof(LingoGlobalAttribute)))
26 | field.SetValue(movieScript, null);
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/Render/RenderStageCompletedView.axaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/EditorContentView.axaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Drizzle.Ported/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Ported;
2 |
3 | public enum TileGeometry
4 | {
5 | Air = 0,
6 | SolidWall = 1,
7 | SlopeBL = 2,
8 | SlopeBR = 3,
9 | SlopeTL = 4,
10 | SlopeTR = 5,
11 | Floor = 6,
12 | // I found reference to these two in a random cast member but they don't seem used anywhere.
13 | //Shortcut = 7,
14 | //Nn = 8,
15 | ///
16 | /// Invisible wall.
17 | ///
18 | Glass = 9
19 | }
20 |
21 | public enum TileFeature
22 | {
23 | BeamHorizontal = 1,
24 | BeamVertical = 2,
25 | Hive = 3,
26 | ShortcutEntrance = 4,
27 | Shortcut = 5,
28 | Entrance = 6,
29 | DragonDen = 7,
30 | Rock = 9,
31 | Spear = 10,
32 | Crack = 11,
33 | ForbidFlyChains = 12,
34 | GarbageWormHole = 13,
35 | Waterfall = 18,
36 | WhackAMoleHole = 19,
37 | WormGrass = 20,
38 | ScavengerHole = 21,
39 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/EditorTabs/TabLevelOverviewView.axaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/Render/RenderStageErrorView.axaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Drizzle.Logic.Tests/Drizzle.Logic.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LingoSource/getExtraTile.lingo:
--------------------------------------------------------------------------------
1 | global extraBufferTiles, newSize
2 |
3 | on change me
4 | --put "HEJ" & me.spriteNum
5 | --extraBufferTiles[me.spriteNum-49] = value(sprite(me.spriteNum).text)
6 | if(me.spriteNum = 48) then
7 | newSize[1] = value(sprite(me.spriteNum).text)
8 | else if(me.spriteNum = 49) then
9 | newSize[2] = value(sprite(me.spriteNum).text)
10 | else if(me.spriteNum = 50) then
11 | extraBufferTiles[1] = value(sprite(me.spriteNum).text)
12 | else if(me.spriteNum = 51) then
13 | extraBufferTiles[2] = value(sprite(me.spriteNum).text)
14 | else if(me.spriteNum = 52) then
15 | extraBufferTiles[3] = value(sprite(me.spriteNum).text)
16 | else if(me.spriteNum = 53) then
17 | extraBufferTiles[4] = value(sprite(me.spriteNum).text)
18 | else if(me.spriteNum = 54) then
19 | newSize[3] = value(sprite(me.spriteNum).text)
20 | else if(me.spriteNum = 55) then
21 | newSize[4] = value(sprite(me.spriteNum).text)
22 | end if
23 | end
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/Render/RenderStageLightView.axaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/Render/RenderStageLayersView.axaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/LingoSource/envEditorStart.lingo:
--------------------------------------------------------------------------------
1 | global gLOprops, gLeProps, gEnvEditButtons, gLastEnvEditButtons
2 |
3 |
4 | on exitFrame me
5 | cols = gLOprops.size.loch
6 | rows = gLOprops.size.locv
7 |
8 | -- member("TEimg1").image = image(cols*5, rows*4, 16)
9 | -- member("TEimg2").image = image(cols*5, rows*4, 16)
10 | -- member("TEimg3").image = image(cols*5, rows*4, 16)
11 | --
12 | -- member("levelEditImageShortCuts").image = image(cols*5, rows*5, 1)
13 |
14 | repeat with l = 1 to 3 then
15 | miniLvlEditDraw(l)
16 | end repeat
17 |
18 | gEnvEditButtons = [#w:0, #f:0]
19 | gLastEnvEditButtons = gEnvEditButtons.duplicate()
20 | end
21 |
22 |
23 |
24 | on checkKey me, key
25 | rtrn = 0
26 | gEnvEditButtons[symbol(key)] = _key.keyPressed(key) and _movie.window.sizeState <> #minimized
27 | if (gEnvEditButtons[symbol(key)])and(gLastEnvEditButtons[symbol(key)]=0) then
28 | rtrn = 1
29 | end if
30 | gLastEnvEditButtons[symbol(key)] = gEnvEditButtons[symbol(key)]
31 | return rtrn
32 | end
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Cast/CastMember.Text.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text;
3 |
4 | namespace Drizzle.Lingo.Runtime.Cast;
5 |
6 | public sealed partial class CastMember
7 | {
8 | private string _text = "";
9 |
10 | public string text
11 | {
12 | get
13 | {
14 | AssertType(CastMemberType.Text);
15 | return _text;
16 | }
17 | set
18 | {
19 | AssertType(CastMemberType.Text);
20 | _text = value;
21 | }
22 | }
23 |
24 | public LingoSymbol alignment { get; set; }
25 |
26 | private void ImportFileImplText(string path)
27 | {
28 | using var sr = new StreamReader(path);
29 | var sb = new StringBuilder();
30 |
31 | while (true)
32 | {
33 | var line = sr.ReadLine();
34 | if (line == null)
35 | break;
36 |
37 | sb.Append(line);
38 | sb.Append('\r');
39 | }
40 |
41 | text = sb.ToString();
42 | }
43 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Data/LingoSymbol.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Drizzle.Lingo.Runtime;
4 |
5 | public readonly struct LingoSymbol : IEquatable
6 | {
7 | public string Value { get; }
8 |
9 | public LingoSymbol(string value)
10 | {
11 | Value = value;
12 | }
13 |
14 | public override string ToString() => $"#{Value}";
15 |
16 |
17 | public static bool operator ==(LingoSymbol a, LingoSymbol b)
18 | {
19 | return a.Value.Equals(b.Value, StringComparison.OrdinalIgnoreCase);
20 | }
21 |
22 | public static bool operator !=(LingoSymbol a, LingoSymbol b)
23 | {
24 | return !(a == b);
25 | }
26 |
27 | public bool Equals(LingoSymbol other)
28 | {
29 | return Value == other.Value;
30 | }
31 |
32 | public override bool Equals(object? obj)
33 | {
34 | return obj is LingoSymbol other && Equals(other);
35 | }
36 |
37 | public override int GetHashCode()
38 | {
39 | return Value.GetHashCode();
40 | }
41 | }
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2021 Pieter-Jan Briers
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Tests/ParseTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using Drizzle.Lingo.Runtime.Parser;
6 | using NUnit.Framework;
7 | using Pidgin;
8 |
9 | namespace Drizzle.Lingo.Tests;
10 |
11 | [Parallelizable(ParallelScope.All)]
12 | [TestFixture]
13 | public sealed class ParseTest
14 | {
15 | private static readonly string SourcesRoot = Path.Combine("..", "..", "..", "..", "LingoSource");
16 |
17 | public static IEnumerable GetSources()
18 | {
19 | return Directory.EnumerateFiles(SourcesRoot, "*.lingo").Select(Path.GetFileName);
20 | }
21 |
22 | [Test]
23 | public void Test([ValueSource(nameof(GetSources))] string fileName)
24 | {
25 | var fullPath = Path.Combine(SourcesRoot, fileName);
26 |
27 | var reader = new StreamReader(fullPath);
28 | var result = LingoParser.Script.ParseOrThrow(reader);
29 |
30 | TestContext.Out.Write("Parsed AST:");
31 | TestContext.Out.Write(DebugPrint.PrintAstNode(result));
32 | }
33 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/MainEditorTabViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Drizzle.Lingo.Runtime;
3 | using Drizzle.Logic;
4 | using ReactiveUI.Fody.Helpers;
5 | using Serilog;
6 |
7 | namespace Drizzle.Editor.ViewModels;
8 |
9 | public sealed class MainEditorTabViewModel : ViewModelBase
10 | {
11 | [Reactive] public string LevelName { get; private set; }
12 | [Reactive] public EditorContentViewModel? Content { get; private set; }
13 |
14 | public MainEditorTabViewModel(string levelName)
15 | {
16 | LevelName = levelName;
17 | }
18 |
19 | public async void InitLoad(Task zygote, string fullPath)
20 | {
21 | var zygoteInstance = await zygote;
22 | var runtime = await Task.Run(() =>
23 | {
24 | var cloned = zygoteInstance.Clone();
25 |
26 | Log.Debug("Loading level...");
27 |
28 | EditorRuntimeHelpers.RunLoadLevel(cloned, fullPath);
29 |
30 | return cloned;
31 | });
32 |
33 | Content = new EditorContentViewModel(runtime);
34 | }
35 | }
--------------------------------------------------------------------------------
/Drizzle.Logic/Rendering/RenderStatus.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Drizzle.Logic.Rendering;
4 |
5 | public record RenderStatus(int CameraIndex, int CountCamerasDone, bool IsPaused, RenderStageStatus Stage);
6 |
7 | public record RenderStageStatus(RenderStage Stage);
8 |
9 | public record RenderStageStatusLayers(int CurrentLayer) : RenderStageStatus(RenderStage.RenderLayers);
10 |
11 | // Pass in stage here due to pre/post effects distinction.
12 | public record RenderStageStatusProps(RenderStage Stage) : RenderStageStatus(Stage);
13 |
14 | public record RenderStageStatusEffects(
15 | int TotalEffectsCount,
16 | int CurrentEffect,
17 | int VertRepeater,
18 | IReadOnlyList EffectNames)
19 | : RenderStageStatus(RenderStage.RenderEffects);
20 |
21 | public record RenderStageStatusLight(int CurrentLayer) : RenderStageStatus(RenderStage.RenderLight);
22 |
23 | public record RenderStageStatusFinalize() : RenderStageStatus(RenderStage.Finalize);
24 |
25 | public record RenderStageStatusRenderColors() : RenderStageStatus(RenderStage.SaveFile);
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/LingoStatus.axaml:
--------------------------------------------------------------------------------
1 |
5 |
17 |
--------------------------------------------------------------------------------
/Drizzle.Benchmarks/Drizzle.Benchmarks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Drizzle, a Rain World level editor
2 |
3 | Drizzle is a port and gradual rewrite of the official Rain World level editor (RWLE). Primary goals are to **make renders faster** and to **have a better interface**.
4 |
5 | ## Compiling and running
6 |
7 | To run drizzle, you currently need to:
8 | 1. `git submodule update --init` to initialize the `Data/` submodule.
9 | 2. run `Drizzle.Transpiler` to transpile the Lingo code to C#.
10 | 3. run `Drizzle.Editor` or `Drizzle.ConsoleApp`, off you go!
11 |
12 | ## Project structure
13 |
14 | The project is organized as such:
15 | * `Drizzle.Lingo.Runtime`: Includes core logic necessary to run Lingo code required by RWLE.
16 | * `Drizzle.Transpiler`: Transpiles Lingo into extremely messy, `dynamic` heavy C#. Requires `Drizzle.Lingo.Runtime` to parse Lingo.
17 | * `Drizzle.Ported`: Contains transpiled C# code output by `Drizzle.Transpiler`.
18 | * `Drizzle.Logic`: Contains C# logic shared between console app and GUI renderer, interfacing with the transpiled code.
19 | * `Drizzle.ConsoleApp`: Console application for headless renders.
20 | * `Drizzle.Editor`: GUI editor using Avalonia.
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Utility/ImageSharpExt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using SixLabors.ImageSharp;
5 | using SixLabors.ImageSharp.PixelFormats;
6 |
7 | namespace Drizzle.Lingo.Runtime;
8 |
9 | public static class ImageSharpExt
10 | {
11 | private const string KRITA = @"C:\Program Files\Krita (x64)\bin\krita.exe";
12 |
13 | public static void ShowImage(this Image img)
14 | {
15 | var tmp = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png");
16 | {
17 | using var file = File.Create(tmp);
18 | img.SaveAsPng(file);
19 | }
20 |
21 | Process.Start(new ProcessStartInfo(KRITA)
22 | {
23 | UseShellExecute = true,
24 | ArgumentList = { tmp }
25 | });
26 | }
27 |
28 | public static Span GetSinglePixelSpan(this Image img) where T : unmanaged, IPixel
29 | {
30 | if (!img.DangerousTryGetSinglePixelMemory(out var memory))
31 | throw new InvalidOperationException("Unable to get single pixel span!");
32 |
33 | return memory.Span;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LingoSource/renderPropsStart.lingo:
--------------------------------------------------------------------------------
1 | global c, keepLooping, afterEffects, gLastImported, gRenderTrashProps, gCurrentlyRenderingTrash, softProp, propsToRender, gPEprops
2 |
3 |
4 | on exitFrame me
5 | type val: number
6 | c = 1
7 | keepLooping = 1
8 | --Set by LevelRenderer.cs now.
9 | --afterEffects = (_movie.frame > 51)
10 | gLastImported = ""
11 | gCurrentlyRenderingTrash = false
12 | if(gRenderTrashProps.count > 0)and(afterEffects=0)then
13 | gCurrentlyRenderingTrash = true
14 | end if
15 |
16 | repeat with q = 0 to 29 then
17 | sprite(50-q).loc = point((1024/2)-q, (768/2)-q)
18 | val = (q.float+1.0)/30.0
19 | sprite(50-q).color = color(val*255, val*255, val*255)
20 | end repeat
21 |
22 | propsToRender = []
23 | repeat with a = 1 to gPEprops.props.count then
24 | propsToRender.add(gPEprops.props[a])
25 | propsToRender[propsToRender.count].addAt(1, propsToRender[propsToRender.count][5].settings.renderOrder)
26 | end repeat
27 | propsToRender.sort()
28 | repeat with a = 1 to propsToRender.count then
29 | propsToRender[a].deleteAt(1)
30 | end repeat
31 |
32 | softProp = void
33 | end
--------------------------------------------------------------------------------
/DrizzleEdit.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | BR
3 | IO
4 | TL
5 | VM
6 | True
7 | True
8 | True
9 | True
--------------------------------------------------------------------------------
/LingoSource/exportAllBitmaps.lingo:
--------------------------------------------------------------------------------
1 | on saveImages savePath
2 | retVal = 1
3 | -- check savePath
4 | if (not stringP(savePath)) and (not savePath contains the dirSeparator) then
5 | retVal = -1
6 | return retVal
7 | else
8 | if the last char of savePath <> the dirSeparator then
9 | savePath = savePath & the dirSeparator
10 | end if
11 | end if
12 |
13 | -- create instance of ImgXtra
14 | imgObj = xtra("ImgXtra").new()
15 |
16 | -- iterate through the Internatl Cast
17 | -- and save as bmp using the member name,
18 | -- or if empty then "member_#"
19 | m = castLib(4).member.count
20 | repeat with i = 1 to m
21 | if member(i, 4).type = #bitmap then
22 | fName = member(i, 4).name & ".bmp"
23 | if fName = ".bmp" then fName = "member_" & i & ".bmp"
24 | put "savePath: " & savePath & fName
25 | ixErr = imgObj.ix_saveImage(["image": member(i, 4).image, "filename": savePath & fName, "format": "BMP"])
26 | if ixErr = 0 then
27 | retVal = -2
28 | end if
29 | end if
30 | end repeat
31 |
32 | -- destroy instance of ImgXtra
33 | imgXtra = 0
34 |
35 | return retVal
36 | end
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoGlobal.Scripting.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 | using Drizzle.Lingo.Runtime.Parser;
4 | using Drizzle.Lingo.Runtime.Scripting;
5 | using Pidgin;
6 |
7 | namespace Drizzle.Lingo.Runtime;
8 |
9 | [SuppressMessage("ReSharper", "InconsistentNaming")]
10 | public sealed partial class LingoGlobal
11 | {
12 | public LingoScriptRuntime ScriptRuntime { get; private set; } = default!;
13 |
14 | public dynamic? value(string a)
15 | {
16 | var trimmed = a.AsSpan().Trim();
17 | if (trimmed.IsEmpty)
18 | return new LingoNumber(0); // value() returns zero on empty string.
19 |
20 | // NOTE: This uses ExpressionNoOps, so expressions like "5 + 10" aren't gonna be parsed correctly.
21 | // This is fine for the level editor, but if you ever do something funny, you've been warned.
22 | try
23 | {
24 | var parsedExpression = LingoParser.ExpressionNoOps.ParseOrThrow(trimmed);
25 | return Interpreter.Evaluate(parsedExpression, LingoRuntime);
26 | }
27 | catch
28 | {
29 | return null;
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/LingoSource/sliderBehav.lingo:
--------------------------------------------------------------------------------
1 |
2 | global gLOprops, gEditLizard, gLevel
3 |
4 | on mouseWithin(me)
5 | sprite(me.spriteNum).color = color(255,0,0)
6 | -- if(gLOprops.mouseClick) then
7 | -- put sprite(me.spriteNum).member.name
8 | -- script("levelOverview").buttonClicked(sprite(me.spriteNum).member.name)
9 | -- gLOprops.mouseClick = 0
10 | -- end if
11 | if _mouse.mouseDown then
12 | -- put me.spriteNum
13 | val = restrict(_mouse.mouseLoc.locH, 50, 450)-50
14 | sprite(me.spriteNum).loch = val+50
15 |
16 | case sprite(me.spriteNum).member.name of
17 | "tileSeedSlider":
18 | gLOprops.tileSeed = val
19 | put "seed changed!"
20 | the randomSeed = gLOprops.tileSeed
21 | end case
22 | end if
23 |
24 | case sprite(me.spriteNum).member.name of
25 |
26 | "tileSeedSlider":
27 | member("buttonText").text = "Tile random seed:" && string(gLOprops.tileSeed)
28 | end case
29 | end mouseWithin
30 |
31 | on mouseLeave(me)
32 | sprite(me.spriteNum).color = color(0,0,0)
33 | member("buttonText").text = ""
34 | sprite(20).quad = [point(-100,-100), point(-100,-100), point(-100,-100), point(-100,-100)]
35 | end mouseLeave
--------------------------------------------------------------------------------
/Drizzle.Editor/Helpers/TrickHitTestOperation.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Media;
3 | using Avalonia.Media.Immutable;
4 | using Avalonia.Platform;
5 | using Avalonia.Rendering.SceneGraph;
6 |
7 | namespace Drizzle.Editor.Helpers;
8 |
9 | public sealed class TrickHitTestOperation : ICustomDrawOperation
10 | {
11 | /*
12 | private readonly ImmutablePen _penRed = new ImmutablePen(Brushes.Red);
13 | private readonly ImmutableSolidColorBrush _brushBlue = new ImmutableSolidColorBrush(new Color(0x80, 0x80, 0x80, 0xff));
14 | */
15 |
16 | public TrickHitTestOperation(Rect bounds)
17 | {
18 | Bounds = bounds;
19 | }
20 |
21 | public void Dispose()
22 | {
23 | }
24 |
25 | public bool HitTest(Point p)
26 | {
27 | return Bounds.Contains(p);
28 | }
29 |
30 | public void Render(IDrawingContextImpl context)
31 | {
32 | // context.DrawRectangle(_brushBlue, _penRed, new RoundedRect(Bounds));
33 | }
34 |
35 | public Rect Bounds { get; }
36 |
37 | public bool Equals(ICustomDrawOperation? other)
38 | {
39 | return other is TrickHitTestOperation { Bounds: var b } && b == Bounds;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/LingoSource/lightEditorStart.lingo:
--------------------------------------------------------------------------------
1 | global gTEprops, gTiles, gEEprops, gLightEProps, firstFrame, geverysecond, glgtimgQuad, gDirectionKeys,gLOprops
2 |
3 | on exitFrame me
4 | firstFrame = 1
5 | l = [ #m1:1, m2:0, #w:0, #a:0, #s:0, #d:0, #r:0, f:0]
6 | gLightEProps.lastKeys = l.duplicate()
7 | gLightEProps.keys = l.duplicate()
8 |
9 | repeat with l = 1 to 3 then
10 | miniLvlEditDraw(l)
11 | end repeat
12 |
13 | geverysecond = 0
14 |
15 | gDirectionKeys = [0,0,0,0]
16 |
17 | glgtimgQuad = [point(0,0), point(member("lightImage").image.width,0), point(member("lightImage").image.width,member("lightImage").image.height), point(0,member("lightImage").image.height)]
18 |
19 | gLightEProps.lastTm = _system.milliseconds
20 |
21 | sprite(11).member = member("pxl")
22 | sprite(12).member = member("pxl")
23 | gLightEProps.paintShape = "pxl"
24 |
25 | sprite(5).rect = rect(0,0,gLOprops.size.loch*20,gLOprops.size.locv*20)
26 |
27 | sprite(8).rect = rect(0,0,gLOprops.size.loch*20,gLOprops.size.locv*20)
28 |
29 | sprite(9).member = member("lightImage")
30 | sprite(10).member = member("lightImage")
31 | sprite(6).member = member("lightImage")
32 | end
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/Render/RenderStageEffectsViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Avalonia.Media;
5 | using Drizzle.Logic;
6 | using Drizzle.Logic.Rendering;
7 |
8 | namespace Drizzle.Editor.ViewModels.Render;
9 |
10 | public sealed class RenderStageEffectsViewModel : RenderStageViewModelBase
11 | {
12 | public IReadOnlyList Effects { get; }
13 |
14 | public override (int max, int current)? Progress { get; }
15 |
16 | public RenderStageEffectsViewModel(RenderStageStatusEffects status)
17 | {
18 | Effects = status.EffectNames
19 | .Select((x, i) => new RenderSingleEffectViewModel(x, i == status.CurrentEffect - 1))
20 | .ToArray();
21 |
22 | Progress = (status.TotalEffectsCount * 60, (status.CurrentEffect - 1) * 60 + status.VertRepeater);
23 | }
24 | }
25 |
26 | public sealed class RenderSingleEffectViewModel : ViewModelBase
27 | {
28 | public string Name { get; }
29 | public bool Current { get; }
30 |
31 | public RenderSingleEffectViewModel(string name, bool current)
32 | {
33 | Name = name;
34 | Current = current;
35 | }
36 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Scripting/LingoScriptRuntime.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Dynamic;
3 | using System.Linq.Expressions;
4 |
5 | namespace Drizzle.Lingo.Runtime.Scripting;
6 |
7 | public sealed class LingoScriptRuntime
8 | {
9 | private readonly Dictionary _getMemberBinders = new();
10 | private readonly Dictionary _binaryOperationBinders = new();
11 |
12 | public LingoScriptRuntime(LingoGlobal global)
13 | {
14 | Global = global;
15 | }
16 |
17 | public LingoGlobal Global { get; }
18 |
19 | public GetMemberBinder GetGetMemberBinder(string memberName)
20 | {
21 | if (!_getMemberBinders.TryGetValue(memberName, out var binder))
22 | _getMemberBinders[memberName] = binder = new LingoGetMemberBinder(memberName);
23 |
24 | return binder;
25 | }
26 |
27 | public BinaryOperationBinder GetBinaryOperationBinder(ExpressionType type)
28 | {
29 | if (!_binaryOperationBinders.TryGetValue(type, out var binder))
30 | _binaryOperationBinders[type] = binder = new LingoBinaryOperationBinder(type);
31 |
32 | return binder;
33 | }
34 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Helpers/Bresenham.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Drizzle.Logic;
3 |
4 | namespace Drizzle.Editor.Helpers;
5 |
6 | public static class Bresenham
7 | {
8 | public static IEnumerable PlotLine(Vector2i from, Vector2i to)
9 | {
10 | // From https://circuitcellar.com/resources/bresenhams-algorithm/
11 | var (x0, y0) = from;
12 | var (x1, y1) = to;
13 |
14 | var dx = x1 >= x0 ? x1 - x0 : x0 - x1;
15 | var dy = y1 >= y0 ? y0 - y1 : y1 - y0;
16 | var sx = x0 < x1 ? 1 : -1;
17 | var sy = y0 < y1 ? 1 : -1;
18 | var err = dx + dy;
19 | var x = x0;
20 | var y = y0;
21 |
22 | while (true)
23 | {
24 | yield return (x, y);
25 | if (x == x1 && y == y1)
26 | break;
27 |
28 | var e2 = 2 * err;
29 | if (e2 >= dy)
30 | {
31 | // step x
32 | err += dy;
33 | x += sx;
34 | }
35 |
36 | if (e2 <= dx)
37 | {
38 | // step y
39 | err += dx;
40 | y += sy;
41 | }
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Program.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.ReactiveUI;
3 | using Drizzle.Lingo.Runtime.Utils;
4 | using Serilog;
5 | using Serilog.Sinks.SystemConsole.Themes;
6 | using SixLabors.ImageSharp;
7 |
8 | namespace Drizzle.Editor;
9 |
10 | class Program
11 | {
12 | // Initialization code. Don't use any Avalonia, third-party APIs or any
13 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
14 | // yet and stuff might break.
15 | public static void Main(string[] args)
16 | {
17 | CultureFix.FixCulture();
18 |
19 | Configuration.Default.PreferContiguousImageBuffers = true;
20 |
21 | Log.Logger = new LoggerConfiguration()
22 | .MinimumLevel.Debug()
23 | .WriteTo.Console(theme: AnsiConsoleTheme.Literate)
24 | .CreateLogger();
25 |
26 | BuildAvaloniaApp()
27 | .StartWithClassicDesktopLifetime(args);
28 | }
29 |
30 | // Avalonia configuration, don't remove; also used by visual designer.
31 | public static AppBuilder BuildAvaloniaApp()
32 | => AppBuilder.Configure()
33 | .UsePlatformDetect()
34 | .LogToTrace()
35 | .UseReactiveUI();
36 | }
37 |
--------------------------------------------------------------------------------
/Drizzle.Logic/EditorRuntimeHelpers.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using Drizzle.Lingo.Runtime;
3 | using Drizzle.Ported;
4 |
5 | namespace Drizzle.Logic;
6 |
7 | public static class EditorRuntimeHelpers
8 | {
9 | public static void RunStartup(LingoRuntime runtime)
10 | {
11 | var startUp = runtime.CreateScript();
12 |
13 | startUp.exitframe();
14 | }
15 |
16 | public static void RunLoadLevel(LingoRuntime runtime, string filePath)
17 | {
18 | var abs = Path.GetFullPath(filePath);
19 |
20 | var withoutExt = Path.Combine(
21 | Path.GetDirectoryName(abs)!,
22 | Path.GetFileNameWithoutExtension(abs));
23 |
24 | runtime.CreateScript().loadlevel(withoutExt, new LingoNumber(1));
25 | }
26 |
27 | // Effectively afaMvLvlEdit in spelrelaterat
28 | public static TileGeometry GetTileGeomBordered(LingoRuntime runtime, Vector2i vec, int layer)
29 | {
30 | var mv = runtime.MovieScript();
31 | var size = (LingoPoint) mv.gLOprops.size;
32 | if (vec.X < 1 || vec.Y < 1 || vec.X > size.loch || vec.Y > size.locv)
33 | return TileGeometry.SolidWall;
34 |
35 | return (TileGeometry)(int)(LingoNumber)mv.gLEProps.matrix[vec.X][vec.Y][layer][1];
36 | }
37 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/Render/RenderWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia;
3 | using Avalonia.Controls;
4 | using Avalonia.Markup.Xaml;
5 | using Avalonia.Threading;
6 | using Drizzle.Editor.ViewModels.Render;
7 |
8 | namespace Drizzle.Editor.Views.Render;
9 |
10 | public partial class RenderWindow : Window
11 | {
12 | private IDisposable? _renderTimer;
13 |
14 | public RenderWindow()
15 | {
16 | InitializeComponent();
17 | #if DEBUG
18 | this.AttachDevTools();
19 | #endif
20 | }
21 |
22 | private void TopLevel_OnClosed(object? sender, EventArgs e)
23 | {
24 | (DataContext as RenderViewModel)?.StopRender();
25 |
26 | _renderTimer?.Dispose();
27 | }
28 |
29 | private void TopLevel_OnOpened(object? sender, EventArgs e)
30 | {
31 | _renderTimer = DispatcherTimer.Run(() =>
32 | {
33 | UpdateElapsedText();
34 | return true;
35 | }, TimeSpan.FromMilliseconds(50), DispatcherPriority.Background);
36 | }
37 |
38 | private void UpdateElapsedText()
39 | {
40 | if (DataContext is not RenderViewModel vm)
41 | return;
42 |
43 | this.FindControl("ElapsedText").Text = vm.RenderTimeElapsed.ToString(@"mm\:ss\.f");
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/EditorTabs/TabGeometryEditorViewModel.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI.Fody.Helpers;
2 |
3 | namespace Drizzle.Editor.ViewModels.EditorTabs;
4 |
5 | public sealed class TabGeometryEditorViewModel : EditorTabViewModelBase
6 | {
7 | public override string Title => "Geometry";
8 |
9 | public EditorContentViewModel ParentVm { get; }
10 |
11 | [Reactive] public GeometryPlacementTool PlacingTool { get; set; } = GeometryPlacementTool.Wall;
12 |
13 | [Reactive] public bool Layer1Visible { get; set; } = true;
14 | [Reactive] public bool Layer2Visible { get; set; } = true;
15 | [Reactive] public bool Layer3Visible { get; set; } = true;
16 |
17 | public TabGeometryEditorViewModel(EditorContentViewModel parentVm)
18 | {
19 | ParentVm = parentVm;
20 | }
21 | }
22 |
23 | public enum GeometryPlacementTool : byte
24 | {
25 | // Tile geometry
26 | Wall,
27 | Slope,
28 | Floor,
29 | Glass,
30 |
31 | // Tile features
32 | BeamHorizontal,
33 | BeamVertical,
34 | Hive,
35 | ShortcutEntrance,
36 | Shortcut,
37 | Entrance,
38 | DragonDen,
39 | Rock,
40 | Spear,
41 | Crack,
42 | ForbidFlyChains,
43 | GarbageWormHole,
44 | Waterfall,
45 | WhackAMoleHole,
46 | WormGrass,
47 | ScavengerHole,
48 | }
--------------------------------------------------------------------------------
/Drizzle.Logic/Rendering/RenderCmd.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Drizzle.Logic.Rendering;
4 |
5 | public abstract record RenderCmd;
6 |
7 | public record RenderCmdSetPaused(bool Paused) : RenderCmd;
8 |
9 | public record RenderCmdSingleStep : RenderCmd;
10 |
11 | public record RenderCmdCancel : RenderCmd;
12 |
13 | public record RenderCmdExec(Action Action) : RenderCmd;
14 |
15 | ///
16 | /// The rendering thread may send a set of preview images for display in the UI.
17 | ///
18 | public record RenderCmdReqPreview : RenderCmd;
19 |
20 | [Serializable]
21 | public class RenderCancelledException : OperationCanceledException
22 | {
23 | public RenderCancelledException()
24 | {
25 | }
26 |
27 | public RenderCancelledException(string message) : base(message)
28 | {
29 | }
30 |
31 | public RenderCancelledException(string message, Exception inner) : base(message, inner)
32 | {
33 | }
34 | }
35 |
36 | [Serializable]
37 | public class RenderCameraException : Exception
38 | {
39 | public RenderCameraException()
40 | {
41 | }
42 |
43 | public RenderCameraException(string message) : base(message)
44 | {
45 | }
46 |
47 | public RenderCameraException(string message, Exception inner) : base(message, inner)
48 | {
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Tests/Drizzle.Lingo.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 |
6 |
7 |
8 |
9 | all
10 | runtime; build; native; contentfiles; analyzers; buildtransitive
11 |
12 |
13 |
14 |
15 |
16 | all
17 | runtime; build; native; contentfiles; analyzers; buildtransitive
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Drizzle.Editor/FodyWeavers.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
12 |
13 |
14 |
15 |
16 | A comma-separated list of error codes that can be safely ignored in assembly verification.
17 |
18 |
19 |
20 |
21 | 'false' to turn off automatic generation of the XML Schema file.
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Drizzle.Editor/ViewModels/EditorContentViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using Drizzle.Editor.ViewModels.EditorTabs;
5 | using Drizzle.Lingo.Runtime;
6 | using Drizzle.Logic;
7 | using Drizzle.Ported;
8 |
9 | namespace Drizzle.Editor.ViewModels;
10 |
11 | public sealed class EditorContentViewModel : ViewModelBase, ILingoRuntimeManager
12 | {
13 | public LingoRuntime Runtime { get; }
14 |
15 | public IReadOnlyList EditorTabs { get; }
16 | public int CountCameras => (int) MovieScript.gCameraProps.cameras.count;
17 | private MovieScript MovieScript => (MovieScript)Runtime.MovieScriptInstance;
18 |
19 | public EditorContentViewModel(LingoRuntime runtime)
20 | {
21 | Runtime = runtime;
22 |
23 | EditorTabs = new EditorTabViewModelBase[]
24 | {
25 | new TabLevelOverviewViewModel(this),
26 | new TabGeometryEditorViewModel(this),
27 | new TabTileEditorViewModel()
28 | };
29 | }
30 |
31 | public Task Exec(Action action)
32 | {
33 | action(Runtime);
34 | return Task.CompletedTask;
35 | }
36 |
37 | public Task Exec(Func func)
38 | {
39 | return Task.FromResult(func(Runtime));
40 | }
41 | }
--------------------------------------------------------------------------------
/LingoSource/levelEditStart.lingo:
--------------------------------------------------------------------------------
1 | global gLEProps, gLOprops, gDirectionKeys
2 |
3 | on exitFrame me
4 |
5 | cols = gLOprops.size.loch
6 | rows = gLOprops.size.locv
7 | member("levelEditImage1").image = image(52*16, 40*16, 16)
8 | member("levelEditImage2").image = image(52*16, 40*16, 16)
9 | member("levelEditImage3").image = image(52*16, 40*16, 16)
10 | member("levelEditImageShortCuts").image = image(52*16, 40*16, 16)
11 | lvlEditDraw(rect(1,1,cols,rows), 1)
12 | lvlEditDraw(rect(1,1,cols,rows), 2)
13 | lvlEditDraw(rect(1,1,cols,rows), 3)
14 | drawShortCutsImg(rect(1,1,cols,rows), 16)
15 |
16 | gDirectionKeys = [0,0,0,0]
17 |
18 | repeat with q = 800 to 820 then
19 | sprite(q).visibility = 1
20 | end repeat
21 | sprite(2).visibility = 1
22 | sprite(8).visibility = 1
23 |
24 | member("toolsImage").image = image(gLEProps.toolMatrix[1].count*32, gLEProps.toolMatrix.count*32, 16)
25 | repeat with q = 1 to gLEProps.toolMatrix.count then
26 | repeat with c = 1 to gLEProps.toolMatrix[1].count then
27 | rct = rect((c-1)*32, (q-1)*32, c*32, q*32)
28 | nm = "icon"&gLEProps.toolMatrix[q][c]
29 | member("toolsImage").image.copyPixels(member("icon"&gLEProps.toolMatrix[q][c]).image, rct, rect(0,0,32,32))
30 | end repeat
31 | end repeat
32 |
33 | gLEprops.levelEditors[1].p.mirrorPos = gLOprops.size.loch/2
34 | end
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoSprite.cs:
--------------------------------------------------------------------------------
1 | using Drizzle.Lingo.Runtime.Cast;
2 |
3 | namespace Drizzle.Lingo.Runtime;
4 |
5 | public sealed class LingoSprite
6 | {
7 | public LingoRect rect { get; set; }
8 |
9 | public LingoNumber locv
10 | {
11 | get => loc.locv;
12 | set => loc = new LingoPoint(loch, value);
13 | }
14 |
15 | public LingoNumber loch
16 | {
17 | get => loc.loch;
18 | set => loc = new LingoPoint(value, loch);
19 | }
20 |
21 | public dynamic? visibility { get; set; } // Fairly certain this is invalid.
22 | public LingoNumber visible { get; set; }
23 |
24 | public CastMember? member { get; set; }
25 |
26 | public LingoNumber blend { get; set; } = 100;
27 |
28 | public LingoColor color { get; set; }
29 | public LingoColor bgcolor { get; set; }
30 |
31 | public LingoColor forecolor
32 | {
33 | get => color;
34 | set => color = value;
35 | }
36 | public LingoColor backcolor
37 | {
38 | get => bgcolor;
39 | set => bgcolor = value;
40 | }
41 |
42 | // This is the REGISTRATION POINT
43 | public LingoPoint loc { get; set; }
44 |
45 | public LingoList quad { get; set; } = new();
46 |
47 | public LingoNumber linesize { get; set; }
48 |
49 | public string text { get; set; } = "";
50 |
51 | public LingoSprite()
52 | {
53 |
54 | }
55 | }
--------------------------------------------------------------------------------
/LingoSource/loadLevelStart.lingo:
--------------------------------------------------------------------------------
1 | global projects, ldPrps, gLOADPATH
2 |
3 | on exitFrame me
4 | projects = []
5 |
6 | pth = the moviePath & "LevelEditorProjects" & the dirSeparator
7 | repeat with f in gLOADPATH then
8 | pth = pth & the dirSeparator & f
9 | end repeat
10 |
11 | fileList = [ ]
12 | repeat with i = 1 to 300 then
13 | n = getNthFileNameInFolder(pth, i)
14 | if n = EMPTY then exit repeat
15 | if (char n.length-3 of n <> ".")then
16 | projects.add("#" & n)
17 | else
18 | fileList.append(n)
19 | end if
20 | end repeat
21 |
22 |
23 |
24 |
25 | repeat with l in fileList then
26 | if chars(l, l.length-3, l.length) = ".txt" then
27 | projects.add( chars(l, 1, l.length-4))
28 | end if
29 | end repeat
30 |
31 | txt = "Use the arrow keys to select a project. Use enter to open it."
32 | put RETURN after txt
33 | repeat with f in gLOADPATH then
34 | put f & "/" after txt
35 | end repeat
36 | put RETURN after txt
37 | put RETURN after txt
38 | repeat with q in projects then
39 | put q after txt
40 | put RETURN after txt
41 | end repeat
42 |
43 | ldPrps = [#lstUp:1, lstDwn:1, #lft:1, #rgth:1, #currProject:1, #listScrollPos:1, #listShowTotal:30]
44 |
45 | member("ProjectsL").text = txt
46 |
47 | member("PalName").text = "Press 'N' to create a new level. Use left and right arrows to step in and out of subfolders"
48 | end
--------------------------------------------------------------------------------
/Drizzle.Lingo.Tests/LingoImagePixelOpsTest.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using System.Runtime.Intrinsics;
3 | using Drizzle.Lingo.Runtime;
4 | using NUnit.Framework;
5 | using SixLabors.ImageSharp.PixelFormats;
6 |
7 | namespace Drizzle.Lingo.Tests;
8 |
9 | [TestFixture]
10 | [Parallelizable(ParallelScope.All)]
11 | [TestOf(typeof(LingoImage))]
12 | public sealed class LingoImagePixelOpsTest
13 | {
14 | [Test]
15 | public void TestL8Read8()
16 | {
17 | var data = new byte[16];
18 | data[3] = 123;
19 |
20 | var result = LingoImage.PixelOpsL8.Read8(
21 | MemoryMarshal.Cast(data),
22 | 0,
23 | Vector256.AllBitsSet);
24 | }
25 |
26 | [Test]
27 | public void TestL8Write8()
28 | {
29 | var data = new byte[16];
30 | data[3] = 123;
31 |
32 | LingoImage.PixelOpsL8.Write8(
33 | MemoryMarshal.Cast(data),
34 | 1,
35 | Vector256.AllBitsSet,
36 | Vector256.AllBitsSet.WithElement(3, 0).WithElement(2, 0));
37 | }
38 |
39 | [Test]
40 | public void TestB8G8R8A8Read8()
41 | {
42 | var data = new byte[32];
43 | data[3] = 123;
44 |
45 | var result = LingoImage.PixelOpsBgra32.Read8(
46 | MemoryMarshal.Cast(data),
47 | 0,
48 | Vector256.AllBitsSet);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoGlobal.Movie.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Dynamic;
3 |
4 | namespace Drizzle.Lingo.Runtime;
5 |
6 | public sealed partial class LingoGlobal
7 | {
8 | public Movie _movie { get; private set; } = default!;
9 |
10 | public void go(LingoNumber frame) => _movie.go(frame);
11 | public LingoNumber the_frame => _movie.frame;
12 |
13 | public sealed class Movie
14 | {
15 | private readonly LingoGlobal _global;
16 |
17 | public Window window { get; }
18 |
19 | public Movie(LingoGlobal global)
20 | {
21 | _global = global;
22 | window = new Window(global);
23 | }
24 |
25 | public LingoNumber frame => 0;
26 |
27 | public string path => _global.the_moviePath;
28 |
29 | public dynamic stage => throw new NotImplementedException();
30 |
31 | public void go(LingoNumber newFrame)
32 | {
33 | // score not implemented.
34 | }
35 | }
36 |
37 | public sealed class Window
38 | {
39 | public Window(LingoGlobal lingoGlobal)
40 | {
41 |
42 | }
43 |
44 | // Literally unused except for one set, just return it.
45 | public dynamic appearanceoptions => new ExpandoObject();
46 | public LingoNumber resizable { get; set; }
47 | public LingoRect rect { get; set; }
48 | public LingoSymbol sizestate => new ("normal");
49 | }
50 | }
--------------------------------------------------------------------------------
/LingoSource/massRenderStart.lingo:
--------------------------------------------------------------------------------
1 | global projects, ldPrps, gLOADPATH, massRenderSelectL
2 |
3 | on exitFrame me
4 | pth = the moviePath & the dirSeparator & "LevelEditorProjects"
5 | repeat with f in gLOADPATH then
6 | pth = pth & the dirSeparator & f
7 | end repeat
8 |
9 | projects = []
10 | fileList = [ ]
11 | repeat with i = 1 to 300 then
12 | n = getNthFileNameInFolder(pth, i)
13 | if n = EMPTY then exit repeat
14 | if (char n.length-3 of n <> ".")then
15 | projects.add("#" & n)
16 | else
17 | fileList.append(n)
18 | end if
19 | end repeat
20 |
21 |
22 |
23 |
24 | repeat with l in fileList then
25 | if chars(l, l.length-3, l.length) = ".txt" then
26 | projects.add( chars(l, 1, l.length-4))
27 | end if
28 | end repeat
29 |
30 | txt = "Use the arrow keys to select a project. Use enter to open it."
31 | put RETURN after txt
32 | repeat with f in gLOADPATH then
33 | put f & "/" after txt
34 | end repeat
35 | put RETURN after txt
36 | put RETURN after txt
37 | repeat with q in projects then
38 | put q after txt
39 | put RETURN after txt
40 | end repeat
41 |
42 | ldPrps = [#lstUp:1, lstDwn:1, #lft:1, #rgth:1, #lstEnter:0, #currProject:1, #listScrollPos:1, #listShowTotal:30]
43 |
44 | member("ProjectsL").text = txt
45 |
46 | member("PalName").text = "Press 'A' to select all in folder. Press 'C' to deselect all. Press ENTER to start rendering."
47 | end
--------------------------------------------------------------------------------
/LingoSource/finished.lingo:
--------------------------------------------------------------------------------
1 | global levelName, gSkyColor, gLoadedName, gFullRender, gViewRender, gDecalColors
2 |
3 |
4 | on exitFrame me
5 | if (_key.keyPressed(48) and _movie.window.sizeState <> #minimized)and(gViewRender) then
6 | _movie.go(9)
7 | end if
8 |
9 | if gViewRender = 0 then
10 | levelName = gLoadedName
11 | end if
12 |
13 | repeat with q = 0 to gDecalColors.count-1 then
14 | member("finalImage").image.setPixel(q, 0, gDecalColors[q+1])
15 | end repeat
16 | -- sprite(1).color = gSkyColor
17 | -- put member("levelName").text
18 | -- if (_key.keyPressed(36))or(gViewRender=0) then
19 | -- put levelName
20 | -- if gFullRender then
21 | -- member("finalfg").image.setPixel(0, 0, member("newPalette").image.getPixel(8,0))--skyColor
22 | -- member("finalfg").image.setPixel(1, 0, member("newPalette").image.getPixel(8,1))--fogColor
23 | -- member("finalfg").image.setPixel(2, 0, member("newPalette").image.getPixel(8,2))--blackColor
24 | -- member("finalfg").image.setPixel(3, 0, member("newPalette").image.getPixel(8,3))--itemcolorColor
25 | -- member("finalfg").image.setPixel(2, 1, member("newPalette").image.getPixel(8,4))--menuColor
26 | --
27 | -- member("finalfg").image.setPixel(0, 1, member("effectColor1").image.getPixel(4,0))
28 | -- member("finalfg").image.setPixel(1, 1, member("effectColor2").image.getPixel(4,0))
29 | -- end if
30 | -- else
31 | -- go the frame
32 | --end if
33 | end
34 |
35 |
--------------------------------------------------------------------------------
/Drizzle.Benchmarks/ImageQuadCopy.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Drizzle.Lingo.Runtime;
3 |
4 | namespace Drizzle.Benchmarks;
5 |
6 | [SimpleJob]
7 | public class ImageQuadCopy
8 | {
9 | private readonly LingoImage _srcImage = new(2000, 1200, 32);
10 | private readonly LingoImage _dstImage = new(2000, 1200, 32);
11 | private readonly LingoList _quad = new LingoList
12 | {
13 | new LingoPoint(-64.7406, -62.5193),
14 | new LingoPoint(1911.9667, -18.7121),
15 | new LingoPoint(2087.3266, 1221.7730),
16 | new LingoPoint(-60.2218, 1266.8830)
17 | };
18 |
19 | [GlobalSetup]
20 | public void Setup()
21 | {
22 | const int checkerSize = 20;
23 | var pxl = MakePxl(true);
24 | for (var y = 0; y < 1200/checkerSize; y++)
25 | for (var x = 0; x < 2000/checkerSize; x++)
26 | {
27 | if (x % 2 == 0 ^ y % 2 == 0)
28 | _srcImage.copypixels(pxl, new LingoRect(x * checkerSize, y * checkerSize, (x + 1) * checkerSize, (y + 1) * checkerSize), pxl.rect);
29 | }
30 | }
31 |
32 | [Benchmark]
33 | public void Bench()
34 | {
35 | _dstImage.copypixels(_srcImage, _quad, _srcImage.rect);
36 | }
37 |
38 | private static LingoImage MakePxl(bool markAsSuch = false)
39 | {
40 | var img = new LingoImage(1, 1, 32);
41 | img.setpixel(0, 0, LingoColor.Black);
42 | img.IsPxl = markAsSuch;
43 | return img;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoRuntime.FileSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 |
5 | namespace Drizzle.Lingo.Runtime;
6 |
7 | public partial class LingoRuntime
8 | {
9 | public static readonly string MovieBasePath;
10 |
11 | static LingoRuntime()
12 | {
13 | #if FULL_RELEASE
14 | var path = Path.Combine(Assembly.GetEntryAssembly()!.Location, "..", "Data");
15 | #else
16 | var path = Path.Combine(Assembly.GetEntryAssembly()!.Location, "..", "..", "..", "..", "..", "Data");
17 | #endif
18 | MovieBasePath = Path.GetFullPath(path) + Path.DirectorySeparatorChar;
19 | CastPath = Path.Combine(MovieBasePath, "Cast");
20 | }
21 |
22 | public string GetFilePath(string relPath)
23 | {
24 | var fullPath = Path.Combine(MovieBasePath, relPath);
25 | if (File.Exists(fullPath))
26 | return fullPath;
27 |
28 | // Try case sensitive compare.
29 | var dir = Path.GetDirectoryName(fullPath);
30 | if (dir == null || !Directory.Exists(dir))
31 | return fullPath;
32 |
33 | var origFileName = Path.GetFileName(fullPath.AsSpan());
34 | foreach (var dirFile in Directory.EnumerateFiles(dir))
35 | {
36 | var dirFileName = Path.GetFileName(dirFile.AsSpan());
37 | if (origFileName.Equals(dirFileName, StringComparison.InvariantCultureIgnoreCase))
38 | return dirFile;
39 | }
40 |
41 | return fullPath;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Drizzle.Editor.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 | enable
5 | true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/Cast/CastMember.Bitmap.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime.Cast;
2 |
3 | public partial class CastMember
4 | {
5 | private LingoImage? _image;
6 |
7 | public LingoImage? image
8 | {
9 | get
10 | {
11 | AssertType(CastMemberType.Bitmap);
12 | return _image;
13 | }
14 | set
15 | {
16 | AssertType(CastMemberType.Bitmap);
17 | _image = value;
18 | }
19 | }
20 |
21 | public LingoRect rect
22 | {
23 | get
24 | {
25 | AssertType(CastMemberType.Bitmap);
26 | return _image!.rect;
27 | }
28 | }
29 |
30 | public LingoNumber width
31 | {
32 | get
33 | {
34 | AssertType(CastMemberType.Bitmap);
35 | return image!.width;
36 | }
37 | }
38 |
39 | public LingoNumber height
40 | {
41 | get
42 | {
43 | AssertType(CastMemberType.Bitmap);
44 | return image!.height;
45 | }
46 | }
47 |
48 | public LingoColor getpixel(int x, int y)
49 | {
50 | AssertType(CastMemberType.Bitmap);
51 | return image!.getpixel(x, y);
52 | }
53 |
54 | public LingoColor getpixel(LingoNumber x, LingoNumber y) => getpixel((int)x, (int)y);
55 |
56 | public LingoPoint regpoint { get; set; }
57 |
58 | private void ImportFileImplBitmap(string path)
59 | {
60 | image = LingoImage.LoadFromPath(path).Trimmed();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Tools/logs_to_manifest.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 | import json
4 | from collections import defaultdict
5 | from typing import Dict, DefaultDict
6 |
7 | LOG_FILE_NAME_RE = re.compile(r"\d+_build \((.+?)\).txt")
8 | LOG_CHECKSUM_RE = re.compile(r"checksum\s+(.+?)\s+cam\s+(\d+):\s+([A-F0-9]+)", re.IGNORECASE)
9 |
10 | checksums_parsed: Dict[str, DefaultDict[str, Dict[str, str]]] = {}
11 |
12 | for f in os.listdir("Logs"):
13 | if not (m := LOG_FILE_NAME_RE.match(f)):
14 | continue
15 |
16 | this_file: DefaultDict[str, Dict[str, str]] = defaultdict(dict)
17 | checksums_parsed[m.group(1)] = this_file
18 |
19 | print(f"Opening file {f}")
20 | with open(os.path.join("Logs", f), "r") as log:
21 | while line := log.readline():
22 | if not (m := LOG_CHECKSUM_RE.search(line)):
23 | continue
24 |
25 | room_name = m.group(1)
26 | room_cam = m.group(2)
27 | room_checksum = m.group(3)
28 |
29 | print(f" {room_name}#{room_cam}:\t{room_checksum}")
30 | this_file[room_name][room_cam] = room_checksum
31 |
32 | dataDir = os.path.join("..", "Data", "LevelEditorProjects")
33 | for name, data in checksums_parsed.items():
34 | if name.startswith("World"):
35 | name = os.path.join("World", name[5:])
36 |
37 | checksums_manifest = os.path.join(dataDir, name, "checksums.json")
38 |
39 | with open(checksums_manifest, "w") as manifest:
40 | json.dump(data, manifest, sort_keys=True, indent=4)
41 |
42 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Tests/LingoOperatorTest.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using Drizzle.Lingo.Runtime;
3 | using NUnit.Framework;
4 |
5 | namespace Drizzle.Lingo.Tests;
6 |
7 | [TestFixture]
8 | public sealed class LingoOperatorTest
9 | {
10 | [Test]
11 | [TestCase("5", "7", ExpectedResult = "12")]
12 | [TestCase("point(100, 10)", "point(200, 20)", ExpectedResult = "point(300, 30)")]
13 | [TestCase("point(100, 10)", "5", ExpectedResult = "point(105, 15)")]
14 | [TestCase("5", "point(100, 10)", ExpectedResult = "point(105, 15)")]
15 | [TestCase("5", "rect(10, 100, 1000, 1)", ExpectedResult = "rect(15, 105, 1005, 6)")]
16 | [TestCase("rect(7, 77, 777, 7777)", "rect(10, 100, 1000, 1)", ExpectedResult = "rect(17, 177, 1777, 7778)")]
17 | [TestCase("point(10, 20)", "rect(5, 7, 10, 10)", ExpectedResult = "[15, 27]")]
18 | [TestCase("[1, 2]", "point(100, 200)", ExpectedResult = "[101, 202]")]
19 | [TestCase("[1, [2, 3]]", "100", ExpectedResult = "[101, [102, 103]]")]
20 | [TestCase("[1, [2, 3]]", "[100, 200]", ExpectedResult = "[101, [202, 203]]")]
21 | [TestCase("[1, [2, 3]]", "[100, [200, 300]]", ExpectedResult = "[101, [202, 303]]")]
22 | [TestCase("[1, 2, 3]", "rect(100, 200, 300, 400)", ExpectedResult = "[101, 202, 303]")]
23 | public string TestAdd(string a, string b)
24 | {
25 | var global = new LingoRuntime(Assembly.GetExecutingAssembly()).Global;
26 |
27 | var aVal = global.value(a);
28 | var bVal = global.value(b);
29 |
30 | return global.@string(LingoGlobal.op_add(aVal, bVal).ToString());
31 | }
32 | }
--------------------------------------------------------------------------------
/Drizzle.Lingo.Tests/RngTest.cs:
--------------------------------------------------------------------------------
1 | using Drizzle.Lingo.Runtime;
2 | using NUnit.Framework;
3 |
4 | namespace Drizzle.Lingo.Tests;
5 |
6 | [TestFixture]
7 | public class RngTest
8 | {
9 | [Test]
10 | public void Test()
11 | {
12 | LingoRuntime.RngState state = default;
13 | LingoRuntime.InitRng(ref state);
14 | state.Seed = 5;
15 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(3));
16 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(1));
17 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(1));
18 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(1));
19 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(3));
20 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(2));
21 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(5));
22 | }
23 |
24 | [Test]
25 | public void TestNoClamp()
26 | {
27 | LingoRuntime.RngState state = default;
28 | LingoRuntime.InitRng(ref state);
29 | state.Seed = 5;
30 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(3));
31 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(1));
32 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(1));
33 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(1));
34 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(3));
35 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(2));
36 | Assert.That(LingoRuntime.Random(ref state, 5), Is.EqualTo(5));
37 | }
38 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/AboutWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 | using System.Runtime.Intrinsics.X86;
4 | using Avalonia;
5 | using Avalonia.Controls;
6 | using Avalonia.Markup.Xaml;
7 |
8 | namespace Drizzle.Editor.Views;
9 |
10 | public sealed partial class AboutWindow : Window
11 | {
12 | public AboutWindow()
13 | {
14 | AvaloniaXamlLoader.Load(this);
15 |
16 | #if DEBUG
17 | this.AttachDevTools();
18 | #endif
19 |
20 | var i = 0;
21 | var grid = this.FindControl("InfoGrid");
22 | AddLine("Version:", Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "");
23 | AddLine("Runtime:", RuntimeInformation.FrameworkDescription);
24 | AddLine("Platform:", RuntimeInformation.RuntimeIdentifier);
25 | AddLine("OS:", RuntimeInformation.OSDescription);
26 | AddLine("CPU features:", Avx2.IsSupported ? "AVX2" : "None");
27 |
28 | for (var j = 0; j < i; j++)
29 | {
30 | grid.RowDefinitions.Add(new RowDefinition(GridLength.Auto));
31 | }
32 |
33 | void AddLine(string desc, string value)
34 | {
35 | var txtDesc = new TextBlock { Text = desc };
36 | Grid.SetColumn(txtDesc, 0);
37 | Grid.SetRow(txtDesc, i);
38 |
39 | var txtValue = new TextBlock { Text = value };
40 | Grid.SetColumn(txtValue, 1);
41 | Grid.SetRow(txtValue, i);
42 |
43 | grid.Children.Add(txtDesc);
44 | grid.Children.Add(txtValue);
45 |
46 | i += 1;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Drizzle.Editor/App.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia;
3 | using Avalonia.Controls;
4 | using Avalonia.Controls.ApplicationLifetimes;
5 | using Avalonia.Logging;
6 | using Avalonia.Markup.Xaml;
7 | using Drizzle.Editor.ViewModels;
8 | using Drizzle.Editor.Views;
9 | using Serilog;
10 | using Serilog.Sinks.SystemConsole.Themes;
11 | using LogEventLevel = Serilog.Events.LogEventLevel;
12 |
13 | namespace Drizzle.Editor;
14 |
15 | public class App : Application
16 | {
17 | public override void Initialize()
18 | {
19 | AvaloniaXamlLoader.Load(this);
20 | }
21 |
22 | public override void OnFrameworkInitializationCompleted()
23 | {
24 | #if DEBUG
25 | Logger.Sink = new AvaloniaSeriLogger(new LoggerConfiguration()
26 | .MinimumLevel.Is(LogEventLevel.Warning)
27 | .Enrich.FromLogContext()
28 | .WriteTo.Console(
29 | outputTemplate: "[{Area}] {Message} ({SourceType} #{SourceHash})\n",
30 | theme: AnsiConsoleTheme.Literate)
31 | .CreateLogger());
32 | #endif
33 |
34 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
35 | {
36 | if (!CommandLineArgs.TryParse(desktop.Args, out var parsed))
37 | Environment.Exit(1);
38 |
39 | var viewModel = new MainWindowViewModel();
40 | desktop.MainWindow = new MainWindow
41 | {
42 | DataContext = viewModel,
43 | };
44 | desktop.ShutdownMode = ShutdownMode.OnMainWindowClose;
45 |
46 | viewModel.Init(parsed);
47 | }
48 |
49 | base.OnFrameworkInitializationCompleted();
50 | }
51 | }
--------------------------------------------------------------------------------
/LingoSource/renderLightStart2.lingo:
--------------------------------------------------------------------------------
1 | global q, c, tm, dptsL, mvL, gLightEProps
2 |
3 | on exitFrame me
4 |
5 | q = 1
6 | c = 1
7 |
8 |
9 | tm = _system.milliseconds
10 |
11 | repeat with q = 0 to 19 then
12 | sprite(40-q).loc = sprite(40-q).loc + point(-q, -q)
13 | member("layer"&string(q)&"sh").image = image(1040,800,32)
14 | end repeat
15 |
16 |
17 |
18 | member("dpImage").image = image(1040,800,32)
19 | member("dpImage").image.copyPixels(member("pxl").image, rect(0,0,1040,800), rect(0,0,1,1), {#color:255})
20 |
21 | smpl = image(4,1,32)
22 | smplPs = 0
23 | dptsL = []
24 |
25 | repeat with q = 1 to 20 then
26 | dp = 20-q-5
27 |
28 |
29 |
30 | pstRct = rect(depthPnt(point(0,0),dp),depthPnt(point(1040,800),dp))
31 | member("dpImage").image.copyPixels(member("layer"&string(20-q)).image, pstRct, rect(0,0,1040,800), {#ink:36, #color:color(255,255,255)})
32 | smpl.copyPixels(member("pxl").image, rect(smplPs,0,4,1), rect(0,0,1,1), {#color:0})
33 |
34 | if (dp+5=12)or(dp+5=8)or(dp+5=4)then
35 |
36 | smpl.copyPixels(member("pxl").image, rect(0,0,4,1), rect(0,0,1,1), {#blend:10, #color:255})
37 | smplPs = smplPs + 1
38 | member("dpImage").image.copyPixels(member("pxl").image, rect(0,0,1040,800), rect(0,0,1,1), {#blend:10, #color:255})
39 | end if
40 |
41 | end repeat
42 |
43 |
44 | repeat with q = 1 to 4 then
45 | dptsL.add(smpl.getPixel(4-q, 0))
46 | end repeat
47 | --put dptsL
48 |
49 |
50 | ang = gLightEProps.lightAngle
51 | ang = degToVec(ang)*2.8
52 | flatness = 1
53 |
54 | mvL = [[ang.locH, ang.locV,1]]
55 | repeat with q = 1 to gLightEProps.flatness then
56 | mvL.add([ang.locH, ang.locV,0])
57 | end repeat
58 | end
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/Render/RenderStageEffectsView.axaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/LingoSource/envEditorLoop.lingo:
--------------------------------------------------------------------------------
1 | global gLOprops, gEnvEditorProps
2 |
3 |
4 | on exitFrame me
5 | script("levelOverview").goToEditor()
6 |
7 | if gLOprops.size.locH > gLOprops.size.locV then
8 | fac = 1024.0/gLOprops.size.locH
9 | else
10 | fac = 768.0/gLOprops.size.locV
11 | end if
12 | rct = rect(1024/2, 768/2, 1024/2, 768/2) + rect(-gLOprops.size.locH*0.5*fac, -gLOprops.size.locV*0.5*fac, gLOprops.size.locH*0.5*fac, gLOprops.size.locV*0.5*fac)
13 |
14 |
15 |
16 | repeat with q = 1 to 2 then
17 | sprite(q).rect = rct
18 | end repeat
19 |
20 |
21 | sprite(4).rect = rct
22 |
23 | if gEnvEditorProps.waterLevel >= 0 then
24 | sprite(3).visibility = true
25 | sprite(5).visibility = true
26 | h = rct.bottom - (gEnvEditorProps.waterLevel+gLOprops.extraTiles[4]+0.5)*fac
27 | sprite(3).rect = rect(rct.left-2, h-1, rct.right+2, 768)
28 | sprite(5).rect = rect(rct.left-2, h-1, rct.right+2, 768)
29 | if gEnvEditorProps.waterInFront then
30 | sprite(3).blend = 5
31 | sprite(5).blend = 50
32 | else
33 | sprite(3).blend = 50
34 | sprite(5).blend = 5
35 | end if
36 | else
37 | sprite(3).visibility = false
38 | sprite(5).visibility = false
39 | end if
40 |
41 | if (_key.keyPressed("l") and _movie.window.sizeState <> #minimized)then
42 | waterLevel = gLOprops.size.locv - gLOprops.extraTiles[2] - gLOprops.extraTiles[4] - (_mouse.mouseLoc.locV/fac).integer
43 | gEnvEditorProps.waterLevel = waterLevel
44 | end if
45 |
46 | if(script("envEditorStart").checkKey("w")) then
47 | if gEnvEditorProps.waterLevel = -1 then
48 | gEnvEditorProps.waterLevel = gLOprops.size.locv/2
49 | else
50 | gEnvEditorProps.waterLevel = -1
51 | end if
52 | end if
53 |
54 | if(script("envEditorStart").checkKey("f")) then gEnvEditorProps.waterInFront = 1 - gEnvEditorProps.waterInFront
55 | go the frame
56 | end
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/LingoSource/LOstart.lingo:
--------------------------------------------------------------------------------
1 | global gLOprops, gEditLizard, gLevel, gLeProps, gPrioCam
2 |
3 | on exitFrame me
4 | cols = gLOprops.size.loch
5 | rows = gLOprops.size.locv
6 | -- member("levelEditImage1").image = image(cols*5, rows*5, 1)
7 | -- member("levelEditImage2").image = image(cols*5, rows*5, 1)
8 | -- member("levelEditImage3").image = image(cols*5, rows*5, 1)
9 |
10 |
11 | -- sprite(21).member = member("libPal" & string(gLOprops.pal))
12 | --sprite(22).member = member("ecol" & string(gLOprops.eCol1))
13 | --sprite(23).member = member("ecol" & string(gLOprops.eCol2))
14 |
15 | gEditLizard = ["pink", 0, 0, 0]
16 | script("levelOverview").nextHole()
17 | member("addLizardTime").text = "0"
18 | member("addLizardFlies").text = "0"
19 | sprite(43).color = color(255, 0, 255)
20 |
21 | sprite(2).loc = point(312,312)+point(-1000+1000*gLevel.defaultTerrain, 0)
22 |
23 | sprite(56).visibility = 1
24 | sprite(57).visibility = 1
25 | sprite(58).visibility = 1
26 | sprite(59).visibility = 1
27 |
28 | sprite(67).loch = (gLEVEL.waterDrips*8)+50
29 | sprite(68).loch = (gLEVEL.maxFlies*10)+50
30 | sprite(69).loch = (gLEVEL.flySpawnRate*4)+50
31 | member("lightTypeText").text = gLevel.lightType
32 | sprite(70).loch = (gLOProps.tileseed)+50
33 |
34 | script("levelOverview").updateLizardsList()
35 |
36 | repeat with q = 0 to 29 then
37 | member("layer"&q).image = image(1,1,1)
38 | member("layer"&q&"sh").image = image(1,1,1)
39 | end repeat
40 |
41 | l = ["Dull", "Reflective", "Superflourescent"]
42 | member("color glow effects").text = l[gLOprops.colGlows[1]+1] && return && l[gLOprops.colGlows[2]+1]
43 |
44 | sprite(22).rect = rect(-100, -100, -100, -100)
45 | if(gPrioCam = 0) then
46 | member("PrioCamText").text = ""
47 | else
48 | member("PrioCamText").text = "Will render camera " & gPrioCam & " first"
49 | end if
50 |
51 | the randomSeed = _system.milliseconds
52 | end
--------------------------------------------------------------------------------
/Drizzle.Editor/Helpers/LingoImageAvaloniaHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia;
3 | using Avalonia.Media.Imaging;
4 | using Avalonia.Platform;
5 | using Drizzle.Lingo.Runtime;
6 | using SixLabors.ImageSharp.PixelFormats;
7 |
8 | namespace Drizzle.Editor.Helpers;
9 |
10 | public static class LingoImageAvaloniaHelper
11 | {
12 | public static unsafe Bitmap LingoImageToBitmap(LingoImage img, bool thumbnail)
13 | {
14 | var finalImg = img;
15 |
16 | if (thumbnail)
17 | {
18 | var copyImg = new LingoImage(50, 50, 32);
19 | copyImg.copypixels(img, copyImg.rect, img.rect);
20 | finalImg = copyImg;
21 | }
22 | else if (img.Depth != 32)
23 | {
24 | var copyImg = new LingoImage(img.Width, img.Height, 32);
25 | copyImg.copypixels(img, img.rect, img.rect);
26 | finalImg = copyImg;
27 | }
28 |
29 | var bgra = finalImg;
30 |
31 | fixed (byte* data = finalImg.ImageBuffer)
32 | {
33 | return new Bitmap(
34 | PixelFormat.Bgra8888,
35 | AlphaFormat.Unpremul,
36 | (nint)data,
37 | new PixelSize(bgra.Width, bgra.Height),
38 | new Vector(96, 96),
39 | sizeof(Bgra32) * bgra.Width);
40 | }
41 | }
42 |
43 | public static unsafe void CopyToBitmap(LingoImage image, WriteableBitmap bitmap)
44 | {
45 | using var locked = bitmap.Lock();
46 | if (locked.Format != PixelFormat.Bgra8888 || image.Depth != 32)
47 | throw new InvalidOperationException();
48 |
49 | if (locked.Size.Width != image.Width || locked.Size.Height != image.Height)
50 | throw new InvalidOperationException();
51 |
52 | // Wow I can't believe that worked.
53 | var dstSpan = new Span((void*)locked.Address, locked.RowBytes * locked.Size.Height);
54 | image.ImageBufferNoPadding.CopyTo(dstSpan);
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/lingo notes.md:
--------------------------------------------------------------------------------
1 | # Notes about Lingo/Director
2 |
3 | This just contains various bits of detail I figured I should write down about lingo/director.
4 |
5 | ## Math
6 |
7 | Lingo has two number types, integers and floats.
8 | * Integers are standard 32 bit signed integers.
9 | * Floats are IEEE 754 double precision. They can contain Infinity, -Infinity and NaN (`INF`, `-INF` and `NAN` is used when printed).
10 |
11 | Doing operations on int generally returns int (operators do including div, `sqrt()` does, `tan()` doesn't which is probably fair). Float returns float.
12 |
13 | `point` and `rect` remember which type their components are constructed out of. So `point(0, 0)` is different from `point(0.0, 0)` in calculations (accessing `locH` will give a float instead of a number, and all the consequences of that...). This is absolutely insane but hey.
14 |
15 | Constructing a rect from two points rounds the points' components though. Yeah. *Sigh*.
16 |
17 | ## Images
18 |
19 | * Images are 0-indexed, so 0,0 is the top left corner. Stuff like `copyPixels()` rectangles all uses sane indexing.
20 | * The bitmap view in Director doesn't put 0,0 at the top left corner, you have to scroll to the top left to view the whole image.
21 | * **image depths:**
22 | * 1/2/4/8 are all indexed color.
23 | * 16 is RGBA5551 or similar.
24 | * 32 is RGBA32 with alpha channel only one bit still.
25 | * out-of-bounds reads with `copyPixels()` will basically be treated as if the out of bounds region is empty.
26 | * Copying to a 1-bit image seems somewhat intelligent about whether to pick white or black based on input color. Primary colors (like pure red) seem to be black, but secondaries like yellow are white. Probably just a specific case of palettization, but still.
27 | * Masked copies position the mask at the top left corner at the source image, and scale the mask 1:1 with the source image.
28 | * If you have a mask of equal size as a source image and sample the right half of that image, you get the right half of the mask
--------------------------------------------------------------------------------
/Drizzle.Logic/Vector2i.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 | using Drizzle.Lingo.Runtime;
4 |
5 | namespace Drizzle.Logic;
6 |
7 | public struct Vector2i : IEquatable
8 | {
9 | public int X;
10 | public int Y;
11 |
12 | public Vector2i(int x, int y)
13 | {
14 | X = x;
15 | Y = y;
16 | }
17 |
18 | public Vector2i(int val)
19 | {
20 | X = val;
21 | Y = val;
22 | }
23 |
24 | public static Vector2i operator +(Vector2i a, Vector2i b) => new(a.X + b.X, a.Y + b.Y);
25 | public static Vector2i operator -(Vector2i a, Vector2i b) => new(a.X - b.X, a.Y - b.Y);
26 | public static Vector2i operator *(Vector2i a, Vector2i b) => new(a.X * b.X, a.Y * b.Y);
27 | public static Vector2i operator /(Vector2i a, Vector2i b) => new(a.X / b.X, a.Y / b.Y);
28 | public static implicit operator Vector2i((int x, int y) tuple) => new(tuple.x, tuple.y);
29 | public static implicit operator LingoPoint(Vector2i v) => new(v.X, v.Y);
30 | public static explicit operator Vector2i(LingoPoint p) => new((int) p.loch, (int) p.locv);
31 |
32 | public void Deconstruct(out int x, out int y)
33 | {
34 | x = X;
35 | y = Y;
36 | }
37 |
38 | public bool Equals(Vector2i other)
39 | {
40 | return X == other.X && Y == other.Y;
41 | }
42 |
43 | public override bool Equals(object? obj)
44 | {
45 | return obj is Vector2i other && Equals(other);
46 | }
47 |
48 | // ReSharper in charge of understanding basic concepts of the language with their analysis.
49 | [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
50 | public override int GetHashCode()
51 | {
52 | return HashCode.Combine(X, Y);
53 | }
54 |
55 | public static bool operator ==(Vector2i left, Vector2i right)
56 | {
57 | return left.Equals(right);
58 | }
59 |
60 | public static bool operator !=(Vector2i left, Vector2i right)
61 | {
62 | return !left.Equals(right);
63 | }
64 | }
--------------------------------------------------------------------------------
/.github/workflows/render-all-levels.yml:
--------------------------------------------------------------------------------
1 | name: render all levels
2 |
3 | concurrency:
4 | group: render_all
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 |
14 | strategy:
15 | fail-fast: false
16 | matrix:
17 | folder:
18 | - "000tests"
19 | - "00_GATE"
20 | - "demos"
21 | - "EditorSamples"
22 | - "templates"
23 | - "testFolder"
24 | - "World/CC"
25 | - "World/DS"
26 | - "World/DU"
27 | - "World/GW"
28 | - "World/HI"
29 | - "World/LF"
30 | - "World/Multi"
31 | - "World/SB"
32 | - "World/SH"
33 | - "World/SI"
34 | - "World/SL"
35 | - "World/SS"
36 | - "World/SU"
37 | - "World/UW"
38 |
39 | steps:
40 | - uses: actions/checkout@v2
41 | with:
42 | submodules: true
43 | - name: Setup .NET
44 | uses: actions/setup-dotnet@v1
45 | with:
46 | dotnet-version: 7.0.x
47 | - name: Restore dependencies
48 | run: dotnet restore
49 | - name: Run transpiler
50 | run: dotnet run --project Drizzle.Transpiler/Drizzle.Transpiler.csproj -- LingoSource Drizzle.Ported/Translated
51 | - name: Build
52 | run: dotnet build --no-restore -c Release
53 | - name: Render levels
54 | shell: pwsh
55 | run: |
56 | $env:COMPlus_gcServer=1
57 | $blackList = @{
58 | #"World/Multi" = @{"Sky Island"=1}
59 | }
60 | $folder = "${{ matrix.folder }}"
61 | $path = join-path "Data/LevelEditorProjects" $folder "*.txt"
62 | $checksum = join-path "Data/LevelEditorProjects" $folder "checksums.json"
63 | $files = (get-childitem -Recurse $path) | where-object { $blackList[$folder] -eq $null -or $blackList[$folder][[System.IO.Path]::GetFileNameWithoutExtension($_)] -ne 1 }
64 | dotnet run --no-build -c Release --project Drizzle.ConsoleApp/Drizzle.ConsoleApp.csproj -- render --parallelism 2 --compare-checksums $checksum $files
65 |
--------------------------------------------------------------------------------
/Drizzle.Lingo.Runtime/LingoRuntime.Random.cs:
--------------------------------------------------------------------------------
1 | namespace Drizzle.Lingo.Runtime;
2 |
3 | public partial class LingoRuntime
4 | {
5 | // Yeah, I reverse engineered Director for this.
6 | // Please don't sue me, Adobe.
7 |
8 | private RngState _rngState;
9 |
10 | public uint RngSeed
11 | {
12 | get => _rngState.Seed;
13 | set
14 | {
15 | InitRng(ref _rngState);
16 | _rngState.Seed = value;
17 | }
18 | }
19 |
20 | public int Random(int clamp)
21 | {
22 | return Random(ref _rngState, clamp);
23 | }
24 |
25 | private static int RandomDerive(uint param)
26 | {
27 | var var1 = (int) ((param << 0xd ^ param) - ((int) param >> 0x15));
28 | var var2 = (uint)(((var1 * var1 * 0x3d73 + 0xc0ae5) * var1 + 0xd208dd0d & 0x7fffffff) + var1);
29 | return (int) ((var2 * 0x2000 ^ var2) - ((int) var2 >> 0x15));
30 | }
31 |
32 | internal static void InitRng(ref RngState state)
33 | {
34 | state.Seed = 1;
35 | // A note here:
36 | // This init field is actually initialized based to another parameter to this function in Director's code.
37 | // It's calculated by substringing a region of the string "Macromedia Director", based on said param.
38 | // I simply hardcoded the value calculated for the Lingo RNG here instead.
39 | state.Init = 0xA3000000;
40 | }
41 |
42 | internal static int Random(ref RngState state, int clamp)
43 | {
44 | if (state.Seed == 0)
45 | InitRng(ref state);
46 |
47 | if ((state.Seed & 1) == 0)
48 | state.Seed = (uint)state.Seed >> 1;
49 | else
50 | state.Seed = (uint)state.Seed >> 1 ^ state.Init;
51 |
52 | int var1 = RandomDerive((uint) (state.Seed * 0x47));
53 | if (clamp > 0)
54 | var1 = (int)((long)(ulong)(var1 & 0x7FFFFFFF) % (long) clamp);
55 |
56 | return var1 + 1;
57 | }
58 |
59 | internal struct RngState
60 | {
61 | public uint Seed;
62 | public uint Init;
63 | }
64 | }
--------------------------------------------------------------------------------
/Drizzle.Editor/Views/MainWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reactive.Disposables;
5 | using Avalonia;
6 | using Avalonia.Controls;
7 | using Avalonia.Input;
8 | using Avalonia.Interactivity;
9 | using Avalonia.Markup.Xaml;
10 | using Avalonia.ReactiveUI;
11 | using Drizzle.Editor.ViewModels;
12 | using ReactiveUI;
13 |
14 | namespace Drizzle.Editor.Views;
15 |
16 | public partial class MainWindow : ReactiveWindow
17 | {
18 | public MainWindow()
19 | {
20 | InitializeComponent();
21 | #if DEBUG
22 | this.AttachDevTools();
23 | #endif
24 |
25 | this.WhenActivated(disposables =>
26 | {
27 | this.WhenAnyValue(x => x.ViewModel!.TabContent!.CountCameras)
28 | .Subscribe(cameras =>
29 | {
30 | var menu = this.FindControl