├── Graph ├── Axis.meta ├── Axis3.meta ├── Axis │ ├── Editor.meta │ ├── Axis3.cs.meta │ └── AxisTic.cs ├── DataViz.meta ├── Graph.cs.meta ├── Graph3.cs.meta ├── Internals.meta ├── Materials.meta ├── Resources.meta ├── Table.cs.meta ├── Scenes │ ├── arrow_head.glb │ ├── arrow_head.blend │ ├── arrow_head.blend1 │ ├── graph_arrow_head.tscn │ ├── axis_tic_z.tscn │ ├── axis_tic_x.tscn │ ├── axis_tic_y.tscn │ └── axis.tscn ├── hexagonal_prism.blend ├── package.json.meta ├── hexagonal_prism.blend1 ├── DataObjects │ ├── BarPlot.cs.meta │ ├── PrimerLine.cs.meta │ ├── StackedArea.cs.meta │ ├── PrimerSurface.cs.meta │ ├── IPrimerGraphData.cs │ ├── SurfacePlot │ │ ├── SurfacePlot_Parametric.gdshader │ │ └── SurfacePlot_Height.gdshader │ ├── CurvePlot2D │ │ └── CurvePlot2DUtilities.cs │ └── PointData.cs ├── FromUnity │ └── TernaryPlot │ │ ├── TernaryPlotUtility.cs.meta │ │ ├── TernaryPointTester.cs.meta │ │ ├── TernaryVectorFieldPlotter.cs.meta │ │ ├── TernaryPlot.cs.meta │ │ ├── TernaryPointTester.cs │ │ └── TernaryVectorFieldPlotter.cs ├── Resources │ ├── Axis.prefab.meta │ ├── Axis3.prefab.meta │ ├── AxisRod.prefab.meta │ ├── AxisTic.prefab.meta │ ├── Graph2.prefab.meta │ ├── Graph3.prefab.meta │ ├── Table.prefab.meta │ ├── AxisArrow.prefab.meta │ ├── TableTicks.prefab.meta │ ├── TernaryPlot.prefab.meta │ ├── YAxisTick.prefab.meta │ ├── AxisTickNoCylinder.prefab.meta │ ├── YAxisTickNoCylinder.prefab.meta │ ├── TernaryPlot.prefab │ ├── Axis.prefab │ ├── YAxisTickNoCylinder.prefab │ ├── AxisArrow.prefab │ └── AxisRod.prefab ├── Editor.meta ├── Primer.Graph.asmdef.meta ├── TernaryPlot.meta ├── hexagonal_prism.tscn ├── package.json ├── Primer.Graph.asmdef ├── Testing │ ├── StackedBarPlotTestScene.tscn │ ├── BarPlot3DTest.cs │ └── StackedBarPlotTest.cs └── TernaryGraphWithBars.cs ├── Utilities ├── arrow_head.blend1 ├── arrow_shaft.blend1 ├── AABBPrinter.cs ├── FPSViewer.cs ├── PrimerGD.cs ├── Pool.cs ├── Vector3Utilities.cs ├── PrimerMathUtils.cs ├── MemoryPool.cs ├── TempDir.cs ├── MeshUtilities.cs ├── ExportedMemberChangeChecker.cs ├── PrimerColor.cs ├── Easing.cs └── Transform3DUtils.cs ├── Gestures ├── Bracket │ ├── bracket.blend │ ├── bracket.fbx │ ├── bracket.glb │ ├── bracket.blend1 │ └── bracket.tscn ├── Arrow │ ├── arrow_head.blend │ ├── arrow_head.blend1 │ ├── arrow_shaft.blend │ ├── arrow_shaft.blend1 │ └── arrow.tscn └── Tests │ └── BracketTestScene.cs ├── .gitignore ├── Simulation ├── Models │ ├── Mango │ │ ├── mango.blend │ │ ├── mango.scn │ │ ├── mango0.bin │ │ ├── mango1.mesh │ │ ├── mango.blend1 │ │ ├── mango.scn.depren │ │ ├── mango2.material │ │ ├── mango2.material.depren │ │ ├── mango_with_physics.scn │ │ ├── textures │ │ │ └── mango2_albedo.png │ │ ├── Mango_Mango_BaseColor 1.jpg │ │ ├── mango_with_physics.scn.depren │ │ ├── Resources │ │ │ └── mango.prefab.scn.depren │ │ ├── spherical_mango_with_physics.scn │ │ └── mango_shape_simplified.tres │ ├── Ground │ │ ├── round_ground.glb │ │ ├── round_ground.blend │ │ ├── round_ground.blend1 │ │ └── test.gdshader │ └── Medium mango tree │ │ ├── mango tree medium.blend │ │ ├── mango tree medium.blend1 │ │ ├── mango tree medium0.bin │ │ ├── mango_tree_medium.blend1 │ │ ├── textures │ │ ├── mango_leaf.png │ │ ├── mango_leaf_grayscale.png │ │ ├── mangotree_1_trunk.material │ │ └── mangotree_1_leaves_albedo.png │ │ └── mango tree medium new.blend ├── ContinuousSpaceTimeSims │ ├── General │ │ ├── Visual │ │ │ ├── IVisualEventManager.cs │ │ │ ├── ForInterchangeableModels │ │ │ │ ├── IVisualEntityFactory.cs │ │ │ │ ├── IVisualEntityWithModel.cs │ │ │ │ └── IVisualModelHandler.cs │ │ │ ├── IVisualizedSystem.cs │ │ │ ├── IVisualEntity.cs │ │ │ ├── VisualEntity.cs │ │ │ └── VisualEntityRegistry.cs │ │ ├── Components │ │ │ ├── IComponent.cs │ │ │ ├── IPhysicsComponent.cs │ │ │ ├── AreaComponent.cs │ │ │ ├── AreaPhysicsComponent.cs │ │ │ └── BodyHandler.cs │ │ ├── Systems │ │ │ └── ISystem.cs │ │ ├── TypedCollision.cs │ │ ├── IDataEntity.cs │ │ ├── Entities │ │ │ └── EntityId.cs │ │ └── CollisionRegistry.cs │ └── Specific │ │ ├── TreeSim │ │ ├── UI │ │ │ └── FruitGrowthSlider.cs │ │ ├── TreeDistributionData.cs │ │ ├── Visual │ │ │ ├── TreeVisualEventManager.cs │ │ │ ├── FruitVisualEventManager.cs │ │ │ ├── TreeVisualEntity.cs │ │ │ └── FruitVisualEntity.cs │ │ ├── Components │ │ │ ├── TreeComponent.cs │ │ │ └── FruitComponent.cs │ │ └── FruitTreeSimSettings.cs │ │ └── CreatureSim │ │ ├── Visual │ │ ├── ICreatureModelHandler.cs │ │ ├── ICreatureFactory.cs │ │ ├── DefaultCreatureFactory.cs │ │ ├── DefaultCreatureModelHandler.cs │ │ └── CreatureVisualEventManager.cs │ │ └── Components │ │ └── CreatureComponent.cs ├── DataVisualization │ └── PeriodicPlotter.cs └── SimSpeedDisplay.cs ├── .idea ├── .idea.PrimerTools │ └── .idea │ │ ├── encodings.xml │ │ ├── vcs.xml │ │ ├── indexLayout.xml │ │ └── .gitignore └── .idea.PrimerToolsGodot.dir │ └── .idea │ ├── encodings.xml │ ├── vcs.xml │ ├── indexLayout.xml │ └── .gitignore ├── LaTeX ├── CLI │ ├── .idea │ │ └── .idea.CLI.dir │ │ │ └── .idea │ │ │ ├── encodings.xml │ │ │ ├── vcs.xml │ │ │ ├── projectSettingsUpdater.xml │ │ │ ├── indexLayout.xml │ │ │ └── workspace.xml │ ├── LatexInput.cs │ ├── CliProgram.cs │ └── LatexBinaries.cs └── TEXTURE_RENDERING_ALTERNATIVE.md ├── StateChangeAnimationSystem ├── IStateChange.cs ├── IAnimatedStateChange.cs ├── AudioStateChange_Future.md ├── MethodTriggerStateChange.cs ├── TestStateChangeSequence.cs └── StateChangeSequence.cs ├── TestScenes ├── tween_test.tscn ├── Godot tests │ └── SyncTest.tscn ├── Latex │ ├── latex_test.tscn │ └── LatexAnimationTest.cs └── Graph │ ├── TernaryGraphTestSequence.cs │ └── GraphTest.cs ├── 2D ├── Diagram │ ├── ExampleDiagram.cs │ ├── ShapeShaders │ │ ├── sdf_common.gdshaderinc │ │ ├── sdf_operations.gdshaderinc │ │ ├── line_shader.gdshader │ │ ├── circle_shader.gdshader │ │ ├── triangle_shader.gdshader │ │ ├── arrow_shader.gdshader │ │ ├── rectangle_shader.gdshader │ │ ├── arrow_shader_solo.gdshader │ │ └── curly_bracket_shader.gdshader │ ├── DiagramSystem.cs │ └── ShapeStyle.cs ├── image_display.gdshader ├── ImageDisplayMesh.cs └── CanvasImitator │ └── CanvasImitator.cs ├── Animation ├── SelfBuildingAnimationTree.cs └── RigidBodyEnsemble.cs ├── Extensions ├── IListExtensions.cs ├── StringExtensions.cs ├── Vector3Extensions.cs ├── Node3DExtensions.cs ├── FloatExtensions.cs └── MeshInstance3DExtensions.cs ├── Environment ├── boilerplate.tscn └── primer_environment.tres └── PrimerConfig.cs /Graph/Axis.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 266d264939154b1bbd27fd57133baad8 3 | timeCreated: 1688463333 -------------------------------------------------------------------------------- /Graph/Axis3.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6816fd71b48b49cab286d424fa030678 3 | timeCreated: 1694372553 -------------------------------------------------------------------------------- /Graph/Axis/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f73834a0b4984fb29b2fab4c1a7083cf 3 | timeCreated: 1694378229 -------------------------------------------------------------------------------- /Graph/DataViz.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fa0fed9b946d4ac2a02a5f77864204a7 3 | timeCreated: 1688478921 -------------------------------------------------------------------------------- /Graph/Graph.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8e9ad337fe7140e380df94ee7829264c 3 | timeCreated: 1666193355 -------------------------------------------------------------------------------- /Graph/Graph3.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8d0187f4237e4d028df9c5b2a447c1e6 3 | timeCreated: 1694372098 -------------------------------------------------------------------------------- /Graph/Internals.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a2a33a1c6b504da4ac0488f61c8f06a8 3 | timeCreated: 1666283938 -------------------------------------------------------------------------------- /Graph/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bf3e1ad6a8d44a50bc8c08af439e4c16 3 | timeCreated: 1688134661 -------------------------------------------------------------------------------- /Graph/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: be55abd55eb64389875a66a9de4b490f 3 | timeCreated: 1667836696 -------------------------------------------------------------------------------- /Graph/Table.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5ec70d8fb66547d5bec919b3d2b79316 3 | timeCreated: 1673882031 -------------------------------------------------------------------------------- /Graph/Axis/Axis3.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9476062e06614695bd569b78056a451c 3 | timeCreated: 1694372575 -------------------------------------------------------------------------------- /Graph/Scenes/arrow_head.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Graph/Scenes/arrow_head.glb -------------------------------------------------------------------------------- /Graph/hexagonal_prism.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Graph/hexagonal_prism.blend -------------------------------------------------------------------------------- /Graph/package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d652fc1f0b424d07abf33f876a2487bd 3 | timeCreated: 1670083279 -------------------------------------------------------------------------------- /Utilities/arrow_head.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Utilities/arrow_head.blend1 -------------------------------------------------------------------------------- /Gestures/Bracket/bracket.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Gestures/Bracket/bracket.blend -------------------------------------------------------------------------------- /Gestures/Bracket/bracket.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Gestures/Bracket/bracket.fbx -------------------------------------------------------------------------------- /Gestures/Bracket/bracket.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Gestures/Bracket/bracket.glb -------------------------------------------------------------------------------- /Graph/Scenes/arrow_head.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Graph/Scenes/arrow_head.blend -------------------------------------------------------------------------------- /Graph/Scenes/arrow_head.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Graph/Scenes/arrow_head.blend1 -------------------------------------------------------------------------------- /Graph/hexagonal_prism.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Graph/hexagonal_prism.blend1 -------------------------------------------------------------------------------- /Utilities/arrow_shaft.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Utilities/arrow_shaft.blend1 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/LaTeX/gltf/ 2 | .aider* 3 | *.uid 4 | *.import 5 | # Tree Distribution saves 6 | **Saved Tree Distributions/ 7 | -------------------------------------------------------------------------------- /Gestures/Arrow/arrow_head.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Gestures/Arrow/arrow_head.blend -------------------------------------------------------------------------------- /Gestures/Arrow/arrow_head.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Gestures/Arrow/arrow_head.blend1 -------------------------------------------------------------------------------- /Gestures/Arrow/arrow_shaft.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Gestures/Arrow/arrow_shaft.blend -------------------------------------------------------------------------------- /Gestures/Bracket/bracket.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Gestures/Bracket/bracket.blend1 -------------------------------------------------------------------------------- /Graph/DataObjects/BarPlot.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c7e697d8fb8244a4a48c28850a4d2b16 3 | timeCreated: 1689852238 -------------------------------------------------------------------------------- /Graph/DataObjects/PrimerLine.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 690059d8e41640a1bd188a214be89dc0 3 | timeCreated: 1689851412 -------------------------------------------------------------------------------- /Graph/DataObjects/StackedArea.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 815170fc31ea4abf97f433a99e19181b 3 | timeCreated: 1688462313 -------------------------------------------------------------------------------- /Gestures/Arrow/arrow_shaft.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Gestures/Arrow/arrow_shaft.blend1 -------------------------------------------------------------------------------- /Graph/DataObjects/PrimerSurface.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed83beb1f1dc41cba5b118f224a8b031 3 | timeCreated: 1689851917 -------------------------------------------------------------------------------- /Simulation/Models/Mango/mango.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/mango.blend -------------------------------------------------------------------------------- /Simulation/Models/Mango/mango.scn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/mango.scn -------------------------------------------------------------------------------- /Simulation/Models/Mango/mango0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/mango0.bin -------------------------------------------------------------------------------- /Simulation/Models/Mango/mango1.mesh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/mango1.mesh -------------------------------------------------------------------------------- /Simulation/Models/Mango/mango.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/mango.blend1 -------------------------------------------------------------------------------- /Simulation/Models/Mango/mango.scn.depren: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/mango.scn.depren -------------------------------------------------------------------------------- /Simulation/Models/Mango/mango2.material: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/mango2.material -------------------------------------------------------------------------------- /Graph/FromUnity/TernaryPlot/TernaryPlotUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 140eb30c981040e8984220f43a7e3ca8 3 | timeCreated: 1689197421 -------------------------------------------------------------------------------- /Graph/FromUnity/TernaryPlot/TernaryPointTester.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4b9d0e346cd8460e8be2d4e03de6e16a 3 | timeCreated: 1689204979 -------------------------------------------------------------------------------- /Simulation/Models/Ground/round_ground.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Ground/round_ground.glb -------------------------------------------------------------------------------- /Graph/FromUnity/TernaryPlot/TernaryVectorFieldPlotter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 35157ccb38064976b83bba2960227b17 3 | timeCreated: 1689351604 -------------------------------------------------------------------------------- /Simulation/Models/Ground/round_ground.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Ground/round_ground.blend -------------------------------------------------------------------------------- /Simulation/Models/Ground/round_ground.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Ground/round_ground.blend1 -------------------------------------------------------------------------------- /Simulation/Models/Mango/mango2.material.depren: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/mango2.material.depren -------------------------------------------------------------------------------- /Simulation/Models/Mango/mango_with_physics.scn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/mango_with_physics.scn -------------------------------------------------------------------------------- /Simulation/Models/Mango/textures/mango2_albedo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/textures/mango2_albedo.png -------------------------------------------------------------------------------- /Simulation/Models/Mango/Mango_Mango_BaseColor 1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/Mango_Mango_BaseColor 1.jpg -------------------------------------------------------------------------------- /Simulation/Models/Mango/mango_with_physics.scn.depren: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/mango_with_physics.scn.depren -------------------------------------------------------------------------------- /Simulation/Models/Mango/Resources/mango.prefab.scn.depren: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/Resources/mango.prefab.scn.depren -------------------------------------------------------------------------------- /Simulation/Models/Mango/spherical_mango_with_physics.scn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Mango/spherical_mango_with_physics.scn -------------------------------------------------------------------------------- /Simulation/Models/Medium mango tree/mango tree medium.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Medium mango tree/mango tree medium.blend -------------------------------------------------------------------------------- /Simulation/Models/Medium mango tree/mango tree medium.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Medium mango tree/mango tree medium.blend1 -------------------------------------------------------------------------------- /Simulation/Models/Medium mango tree/mango tree medium0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Medium mango tree/mango tree medium0.bin -------------------------------------------------------------------------------- /Simulation/Models/Medium mango tree/mango_tree_medium.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Medium mango tree/mango_tree_medium.blend1 -------------------------------------------------------------------------------- /Simulation/Models/Medium mango tree/textures/mango_leaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Medium mango tree/textures/mango_leaf.png -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Visual/IVisualEventManager.cs: -------------------------------------------------------------------------------- 1 | namespace PrimerTools.Simulation; 2 | 3 | public interface IVisualEventManager 4 | { 5 | void Cleanup(); 6 | } -------------------------------------------------------------------------------- /Simulation/Models/Medium mango tree/mango tree medium new.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Medium mango tree/mango tree medium new.blend -------------------------------------------------------------------------------- /Simulation/Models/Medium mango tree/textures/mango_leaf_grayscale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Medium mango tree/textures/mango_leaf_grayscale.png -------------------------------------------------------------------------------- /Simulation/Models/Medium mango tree/textures/mangotree_1_trunk.material: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Medium mango tree/textures/mangotree_1_trunk.material -------------------------------------------------------------------------------- /Simulation/Models/Medium mango tree/textures/mangotree_1_leaves_albedo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Primer-Learning/PrimerTools/HEAD/Simulation/Models/Medium mango tree/textures/mangotree_1_leaves_albedo.png -------------------------------------------------------------------------------- /Graph/Resources/Axis.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b303ed9bc4cdc44e892cde562813803d 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Graph/Resources/Axis3.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bf6e7060d0e32514481bda9a119a81e0 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Graph/Resources/AxisRod.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bcb626d89aeaa184a8f0616dd38cce92 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Graph/Resources/AxisTic.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: abd792ad5726345beaabdf8f95833bb7 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Graph/Resources/Graph2.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 907b49b9bf45c4ac3965bbc2fc858a80 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Graph/Resources/Graph3.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 88417f6cd1fc6f04ca6a547efbba8c94 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Graph/Resources/Table.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a636654243eeb4a9487877d6354b91ea 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Components/IComponent.cs: -------------------------------------------------------------------------------- 1 | namespace PrimerTools.Simulation; 2 | 3 | public interface IComponent 4 | { 5 | EntityId EntityId { get; set; } 6 | void CleanUp(); 7 | } 8 | -------------------------------------------------------------------------------- /Graph/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 97a88585798324a0f82bc4ce265a4d42 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Graph/Resources/AxisArrow.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c9246c75b0bea4296b6d948b371ca68f 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Graph/Resources/TableTicks.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 923d898689e5746d6bad800a3459dce9 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Graph/Resources/TernaryPlot.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c073d278af8ea4602a5004a8453bc906 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Graph/Resources/YAxisTick.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aed2a79473b7bc742b56fb42e8e29ce1 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /.idea/.idea.PrimerTools/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/.idea.PrimerTools/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Graph/Primer.Graph.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f6d0939ee404c415a88a984426da0be3 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Graph/Resources/AxisTickNoCylinder.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 081239890fc37184cba8c3c799f90a39 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Graph/TernaryPlot.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cbc3e11fb187843a9b89714d262516aa 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /.idea/.idea.PrimerToolsGodot.dir/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/.idea.PrimerToolsGodot.dir/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Graph/Resources/YAxisTickNoCylinder.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ab7347d685858fa40ade44dd3a9ce148 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LaTeX/CLI/.idea/.idea.CLI.dir/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Components/IPhysicsComponent.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation; 4 | 5 | public interface IPhysicsObjectHandler 6 | { 7 | public Area3D ConstructDebugNode(Node3D parent); 8 | } -------------------------------------------------------------------------------- /LaTeX/CLI/.idea/.idea.CLI.dir/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Visual/ForInterchangeableModels/IVisualEntityFactory.cs: -------------------------------------------------------------------------------- 1 | namespace PrimerTools.Simulation; 2 | 3 | public interface IVisualEntityFactory where T : IVisualEntity 4 | { 5 | T CreateInstance(); 6 | } 7 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Visual/IVisualizedSystem.cs: -------------------------------------------------------------------------------- 1 | namespace PrimerTools.Simulation; 2 | 3 | public interface IVisualizedSystem 4 | { 5 | IVisualEventManager CreateVisualEventManager(VisualEntityRegistry visualEntityRegistry); 6 | } -------------------------------------------------------------------------------- /LaTeX/CLI/.idea/.idea.CLI.dir/.idea/projectSettingsUpdater.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/.idea.PrimerTools/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /StateChangeAnimationSystem/IStateChange.cs: -------------------------------------------------------------------------------- 1 | // Minimal interface for anything that can be added to a sequence 2 | public interface IStateChange 3 | { 4 | string Name { get; } 5 | double Duration { get; } 6 | IStateChange WithDuration(double duration); 7 | } 8 | -------------------------------------------------------------------------------- /LaTeX/CLI/.idea/.idea.CLI.dir/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/.idea.PrimerToolsGodot.dir/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TestScenes/tween_test.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://cs00kuudx2xtn"] 2 | 3 | [ext_resource type="Script" path="res://addons/PrimerTools/TestScenes/tween_test.gd" id="1_csn08"] 4 | 5 | [node name="TweenTest" type="Node2D"] 6 | script = ExtResource("1_csn08") 7 | -------------------------------------------------------------------------------- /StateChangeAnimationSystem/IAnimatedStateChange.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | public interface IAnimatedStateChange : IStateChange 4 | { 5 | void EvaluateAtTime(double elapsedTime); 6 | void ApplyEndState(); 7 | void RecordStartState(); 8 | void Revert(); 9 | } 10 | -------------------------------------------------------------------------------- /Graph/hexagonal_prism.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://dufftdgcc6vle"] 2 | 3 | [ext_resource type="PackedScene" uid="uid://7hggfooniu2k" path="res://addons/PrimerTools/Graph/hexagonal_prism.blend" id="1_nrpse"] 4 | 5 | [node name="hexagonal_prism" instance=ExtResource("1_nrpse")] 6 | -------------------------------------------------------------------------------- /Graph/Scenes/graph_arrow_head.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://d1y06ar34m5qm"] 2 | 3 | [ext_resource type="PackedScene" uid="uid://c0tb2lpdmwoml" path="res://addons/PrimerTools/Graph/Scenes/arrow_head.glb" id="1_2ompr"] 4 | 5 | [node name="arrow_head" instance=ExtResource("1_2ompr")] 6 | -------------------------------------------------------------------------------- /TestScenes/Godot tests/SyncTest.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://d074sqo558hi3"] 2 | 3 | [ext_resource type="Script" uid="uid://dvs55al8yrnvw" path="res://addons/PrimerTools/TestScenes/Godot tests/SyncTest.cs" id="1_dxfm1"] 4 | 5 | [node name="Node3D" type="Node3D"] 6 | script = ExtResource("1_dxfm1") 7 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Systems/ISystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PrimerTools.Simulation; 4 | 5 | public interface ISystem 6 | { 7 | void Initialize(EntityRegistry registry, SimulationWorld simulationWorld); 8 | void Update(float deltaTime); 9 | event Action Stepped; 10 | } 11 | -------------------------------------------------------------------------------- /Graph/FromUnity/TernaryPlot/TernaryPlot.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 20fc66b1c5d0f48a99a8d807d4cc01e0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Visual/ForInterchangeableModels/IVisualEntityWithModel.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation; 4 | 5 | public interface IVisualEntityWithModel : IVisualEntity 6 | where TModelHandler : IVisualModelHandler 7 | { 8 | TModelHandler ModelHandler { get; } 9 | } 10 | -------------------------------------------------------------------------------- /Graph/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "org.primerlearning.primer-graph", 3 | "displayName": "Primer.Graph", 4 | "version": "1.0.0", 5 | "description": "Primer's graph visualization", 6 | "unity": "2021.3", 7 | "dependencies": { 8 | "org.primerlearning.primer": "1.0.0", 9 | "org.primerlearning.primer-timeline": "1.0.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Visual/IVisualEntity.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation; 4 | 5 | public interface IVisualEntity 6 | { 7 | EntityId EntityId { get; } 8 | Node3D RootNode { get; } 9 | void Initialize(EntityRegistry registry, EntityId entityId); 10 | void Update(EntityRegistry registry); 11 | } 12 | -------------------------------------------------------------------------------- /StateChangeAnimationSystem/AudioStateChange_Future.md: -------------------------------------------------------------------------------- 1 | # Audio State Change System (Future Implementation) 2 | 3 | ## Overview 4 | An `AudioStateChange` class that integrates audio playback into the state change animation system, allowing audio to be scheduled, scrubbed, and speed-controlled alongside visual animations. 5 | 6 | ## Core Implementation Concept 7 | 8 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Visual/ForInterchangeableModels/IVisualModelHandler.cs: -------------------------------------------------------------------------------- 1 | namespace PrimerTools.Simulation; 2 | 3 | /// 4 | /// Marker interface for model handlers used by IVisualEntityWithModel. 5 | /// Ensures type safety in the visual entity system. 6 | /// 7 | public interface IVisualModelHandler 8 | { 9 | 10 | } -------------------------------------------------------------------------------- /.idea/.idea.PrimerTools/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /modules.xml 6 | /.idea.PrimerTools.iml 7 | /contentModel.xml 8 | /projectSettingsUpdater.xml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /.idea/.idea.PrimerToolsGodot.dir/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /modules.xml 6 | /.idea.PrimerToolsGodot.iml 7 | /contentModel.xml 8 | /projectSettingsUpdater.xml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /Graph/DataObjects/IPrimerGraphData.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Graph; 4 | 5 | public interface IPrimerGraphData 6 | { 7 | public void FetchData(); 8 | public Animation Transition(double duration); 9 | public IStateChange TransitionStateChange(double duration); 10 | public Tween TweenTransition(double duration); 11 | public IStateChange Disappear(); 12 | } -------------------------------------------------------------------------------- /2D/Diagram/ExampleDiagram.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools._2D.Diagram; 4 | 5 | [Tool] 6 | public partial class ExampleDiagram : DiagramSystem 7 | { 8 | protected override void DefineDiagram() 9 | { 10 | // Add two circles 11 | // AddElement(new CircleElement(new Vector2(-1, 1), 1f)); 12 | // AddElement(new CircleElement(new Vector2(3, 0), 3f)); 13 | } 14 | } -------------------------------------------------------------------------------- /Graph/Primer.Graph.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Primer.Graph", 3 | "rootNamespace": "Primer.Graph", 4 | "references": [ 5 | "GUID:6055be8ebefd69e48b49212b09b47b2f", 6 | "GUID:f06555f75b070af458a003d92f9efb00", 7 | "GUID:f51ebe6a0ceec4240a699833d6309b23", 8 | "ShapesRuntime", 9 | "Primer", 10 | "Primer.Animation", 11 | "Primer.Timeline", 12 | "Primer.Latex", 13 | "Primer.Shapes" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Graph/Scenes/axis_tic_z.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://dgevknceo3tes"] 2 | 3 | [ext_resource type="PackedScene" uid="uid://c57q0rwh3i0n8" path="res://addons/PrimerTools/Graph/Scenes/axis_tic_x.tscn" id="1_i8m45"] 4 | 5 | [node name="axis_tic" instance=ExtResource("1_i8m45")] 6 | 7 | [node name="LatexNode" parent="." index="1"] 8 | transform = Transform3D(-8.74228e-09, 0, 0.2, 0, 0.2, 0, -0.2, 0, -8.74228e-09, 0, -0.14, 0) 9 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/TypedCollision.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Godot; 3 | 4 | namespace PrimerTools.Simulation; 5 | 6 | public readonly struct TypedCollision 7 | { 8 | public readonly Type EntityType; 9 | public readonly EntityId EntityId; 10 | 11 | public TypedCollision(Type entityType, EntityId entityId) 12 | { 13 | EntityType = entityType; 14 | EntityId = entityId; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/TreeSim/UI/FruitGrowthSlider.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools.Simulation; 3 | 4 | public partial class FruitGrowthSlider : HSlider 5 | { 6 | public override void _Ready() 7 | { 8 | base._Ready(); 9 | Value = FruitTreeSimSettings.FruitGrowthTime; 10 | } 11 | 12 | public override void _ValueChanged(double newValue) 13 | { 14 | FruitTreeSimSettings.FruitGrowthTime = (float) newValue; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Animation/SelfBuildingAnimationTree.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | using PrimerTools; 4 | 5 | [Tool] 6 | public partial class SelfBuildingAnimationTree : AnimationTree 7 | { 8 | private bool _run = false; 9 | [Export] private bool RunButton { 10 | get => _run; 11 | set { 12 | if (!value && _run && Engine.IsEditorHint()) 13 | { 14 | Build(); 15 | } 16 | _run = true; 17 | } 18 | } 19 | 20 | protected virtual void Build() 21 | { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/CreatureSim/Visual/ICreatureModelHandler.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation.ContinuousSpaceTimeSims.CreatureSim; 4 | 5 | public interface ICreatureModelHandler : IVisualModelHandler 6 | { 7 | void OnReady(Node3D nodeCreature); 8 | void Initialize(float normalizedAwareness); 9 | void Update(CreatureComponent creatureComponent); 10 | void TriggerEatAnimation(float duration); 11 | Vector3 GetMouthPosition(); 12 | } -------------------------------------------------------------------------------- /Extensions/IListExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using PrimerTools; 3 | 4 | namespace PrimerTools; 5 | 6 | public static class IListExtensions 7 | { 8 | public static void Shuffle(this IList list, Rng rng) 9 | { 10 | // Same as IEnumerableExtensions.ShuffleToList, but in place 11 | var n = list.Count; 12 | while (n > 1) { 13 | n--; 14 | var k = rng.RangeInt(0, n + 1); 15 | (list[k], list[n]) = (list[n], list[k]); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/CreatureSim/Visual/ICreatureFactory.cs: -------------------------------------------------------------------------------- 1 | using PrimerTools.Simulation.ContinuousSpaceTimeSims.CreatureSim.Visual; 2 | 3 | namespace PrimerTools.Simulation.ContinuousSpaceTimeSims.CreatureSim; 4 | 5 | public interface ICreatureFactory : IVisualEntityFactory 6 | { 7 | ICreatureModelHandler CreateModelHandler(); 8 | 9 | CreatureVisualEntity IVisualEntityFactory.CreateInstance() 10 | { 11 | return new CreatureVisualEntity(CreateModelHandler()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /2D/image_display.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | uniform sampler2D texture_albedo : source_color; 4 | uniform vec2 zoom_center : hint_range(0.0, 1.0) = vec2(0.5, 0.5); 5 | uniform float zoom_factor : hint_range(1.0, 10.0) = 2.0; 6 | 7 | void fragment() { 8 | vec2 uv = UV; 9 | 10 | // Shift UV to center the zoom 11 | uv -= zoom_center; 12 | 13 | // Apply zoom 14 | uv *= zoom_factor; 15 | 16 | // Shift UV back 17 | uv += zoom_center; 18 | 19 | // Sample the texture with modified UV 20 | ALBEDO = texture(texture_albedo, uv).rgb; 21 | } -------------------------------------------------------------------------------- /Graph/Testing/StackedBarPlotTestScene.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://bsm68n5h77ofs"] 2 | 3 | [ext_resource type="Script" uid="uid://c5suyawkyddst" path="res://addons/PrimerTools/Graph/Testing/StackedBarPlotTest.cs" id="1_meheg"] 4 | 5 | [node name="StackedBarPlotTestScene" type="Node3D"] 6 | 7 | [node name="StackedBarPlotTestScript" type="Node3D" parent="."] 8 | script = ExtResource("1_meheg") 9 | Run = true 10 | 11 | [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] 12 | transform = Transform3D(1, 0, 0, 0, 0.869616, 0.493729, 0, -0.493729, 0.869616, 0, 14.41, 6.35957) 13 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/CreatureSim/Visual/DefaultCreatureFactory.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation.ContinuousSpaceTimeSims.CreatureSim.Visual; 4 | 5 | public class DefaultCreatureFactory : ICreatureFactory 6 | { 7 | public ICreatureModelHandler CreateModelHandler() 8 | { 9 | var node3D = new Node3D(); 10 | var meshInstance = new MeshInstance3D(); 11 | meshInstance.Mesh = new SphereMesh(); 12 | node3D.AddChild(meshInstance); 13 | meshInstance.Position = Vector3.Up / 2f; 14 | return new DefaultCreatureModelHandler(node3D); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TestScenes/Latex/latex_test.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=3 uid="uid://l7m5sl6xu412"] 2 | 3 | [ext_resource type="Script" uid="uid://cmvfwbhqujfxe" path="res://addons/PrimerTools/LaTeX/LatexNode.cs" id="1_ktxyh"] 4 | 5 | [sub_resource type="BoxMesh" id="BoxMesh_kqfdf"] 6 | 7 | [node name="Node3D" type="Node3D"] 8 | 9 | [node name="LatexTestNode" type="Node3D" parent="."] 10 | script = ExtResource("1_ktxyh") 11 | Latex = "$0$" 12 | VerticalAlignment = 3 13 | 14 | [node name="MeshInstance3D" type="MeshInstance3D" parent="."] 15 | transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 3.883, 0, 0) 16 | mesh = SubResource("BoxMesh_kqfdf") 17 | -------------------------------------------------------------------------------- /Simulation/Models/Ground/test.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | //render_mode world_vertex_coords 3 | 4 | varying vec3 model_position; 5 | 6 | void vertex() { 7 | // Called for every vertex the material is visible on. 8 | model_position = (MODEL_MATRIX * vec4(VERTEX, .0)).xyz; 9 | //model_position = VERTEX; 10 | } 11 | 12 | void fragment() { 13 | // Called for every pixel the material is visible on. 14 | ALBEDO = model_position; 15 | //ALBEDO = VERTEX; 16 | } 17 | 18 | //void light() { 19 | // Called for every pixel for every light affecting the material. 20 | // Uncomment to replace the default light processing function with this one. 21 | //} 22 | -------------------------------------------------------------------------------- /Utilities/AABBPrinter.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System.Linq; 3 | 4 | [Tool] 5 | public partial class AABBPrinter : VisualInstance3D 6 | { 7 | private bool printBounds = true; 8 | [Export] public bool PrintBounds { 9 | get => printBounds; 10 | set { 11 | var oldPrintBounds = printBounds; 12 | printBounds = value; 13 | if (printBounds && !oldPrintBounds) { // Avoids running on build 14 | PrintBoundingBox(); 15 | } 16 | } 17 | } 18 | 19 | public override void _Ready() 20 | { 21 | PrintBoundingBox(); 22 | } 23 | 24 | private void PrintBoundingBox() 25 | { 26 | GD.Print("Bounds: " + GetAabb().Position, GetAabb().End); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/IDataEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Godot; 3 | 4 | namespace PrimerTools.Simulation; 5 | 6 | public interface IDataEntity : IEquatable 7 | { 8 | public int EntityId { get; set; } 9 | public bool Alive { get; set; } 10 | public void CleanUp(); 11 | public void Initialize(Rid space); 12 | 13 | bool IEquatable.Equals(IDataEntity other) 14 | { 15 | if (other is null) return false; 16 | return EntityId == other.EntityId; 17 | } 18 | 19 | bool Equals(object obj) => obj is IDataEntity other && Equals(other); 20 | 21 | int GetHashCode() => EntityId; 22 | } 23 | -------------------------------------------------------------------------------- /2D/Diagram/ShapeShaders/sdf_common.gdshaderinc: -------------------------------------------------------------------------------- 1 | // Common SDF utilities 2 | 3 | float addOuterThickness(float d, float thick) { 4 | return d - thick; 5 | } 6 | 7 | float makeHollow(float d, float thick) { 8 | return -(d + thick); 9 | } 10 | 11 | // Create hollow shape by using absolute value of SDF 12 | float makeHollowAbs(float d, float thick) { 13 | return abs(d) - thick; 14 | } 15 | 16 | // Apply thickness based on whether we're inside or outside the shape 17 | float applyThickness(float d, float outer_thick, float inner_thick) { 18 | if (d < 0.0) { 19 | return makeHollow(d, inner_thick); 20 | } else { 21 | return addOuterThickness(d, outer_thick); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/TreeSim/TreeDistributionData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Godot; 4 | using PrimerTools.Simulation.Components; 5 | 6 | namespace PrimerTools.Simulation; 7 | 8 | [Serializable] 9 | public class TreeDistributionData 10 | { 11 | public List Trees { get; set; } 12 | 13 | // TODO: Just make this use the whole TreeComponent class? 14 | [Serializable] 15 | public struct TreeData 16 | { 17 | public Transform3D Transform; 18 | public float Age { get; set; } 19 | public TreeData(TreeComponent tree) 20 | { 21 | Transform = tree.Body.Transform; 22 | Age = tree.Age; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Utilities/FPSViewer.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools; 4 | 5 | [Tool] 6 | public partial class FPSViewer : Label 7 | { 8 | [Export] private int _maxFPS; 9 | [Export] private bool _printing; 10 | private double _printInterval = 1; 11 | private double _timer; 12 | 13 | public override void _Ready() 14 | { 15 | Engine.MaxFps = _maxFPS; 16 | } 17 | 18 | public override void _Process(double delta) 19 | { 20 | var text = $"{Engine.GetFramesPerSecond()} FPS"; 21 | Text = text; 22 | 23 | if (!_printing) return; 24 | _timer += delta; 25 | if (!(_timer >= _printInterval)) return; 26 | GD.Print(text); 27 | _timer -= _printInterval; 28 | } 29 | } -------------------------------------------------------------------------------- /Gestures/Bracket/bracket.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=3 uid="uid://cr0auqlg2kiuq"] 2 | 3 | [ext_resource type="PackedScene" uid="uid://dmfd4vojv5g8j" path="res://addons/PrimerTools/Gestures/Bracket/bracket.glb" id="1_slkfe"] 4 | [ext_resource type="Script" uid="uid://d2prwaixeekti" path="res://addons/PrimerTools/Gestures/Bracket/Bracket.cs" id="2_rl31f"] 5 | 6 | [node name="bracket" instance=ExtResource("1_slkfe")] 7 | script = ExtResource("2_rl31f") 8 | 9 | [node name="bracket" parent="." index="0"] 10 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.00499849, 0) 11 | 12 | [node name="bracketTipMesh_Left" parent="bracket" index="4"] 13 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 1) 14 | 15 | [node name="bracketTipMesh_Right" parent="bracket" index="5"] 16 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1) 17 | -------------------------------------------------------------------------------- /Graph/DataObjects/SurfacePlot/SurfacePlot_Parametric.gdshader: -------------------------------------------------------------------------------- 1 | private static ImageTexture BuildHeightTexture(Vector3[,] data, int w, int d) 2 | { 3 | var img = Image.Create(w, d, false, Image.Format.Rf); // 32-bit float R 4 | for (int x = 0; x < w; x++) 5 | for (int z = 0; z < d; z++) 6 | { 7 | float h = data[x, z].Y; 8 | img.SetPixel(x, z, new Color(h, 0, 0, 1)); 9 | } 10 | return ImageTexture.CreateFromImage(img); 11 | } 12 | 13 | private static ImageTexture BuildXYZTexture(Vector3[,] data, int w, int d) 14 | { 15 | var img = Image.Create(w, d, false, Image.Format.Rgbf); // 3×32-bit float 16 | for (int x = 0; x < w; x++) 17 | for (int z = 0; z < d; z++) 18 | { 19 | var p = data[x, z]; 20 | img.SetPixel(x, z, new Color(p.X, p.Y, p.Z, 1f)); 21 | } 22 | return ImageTexture.CreateFromImage(img); 23 | } -------------------------------------------------------------------------------- /2D/Diagram/ShapeShaders/sdf_operations.gdshaderinc: -------------------------------------------------------------------------------- 1 | // SDF operation functions 2 | 3 | float opUnion(float d1, float d2) { 4 | return min(d1, d2); 5 | } 6 | 7 | float opSubtraction(float d1, float d2) { 8 | return max(-d1, d2); 9 | } 10 | 11 | float opIntersection(float d1, float d2) { 12 | return max(d1, d2); 13 | } 14 | 15 | float opSmoothUnion(float d1, float d2, float k) { 16 | float h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0); 17 | return mix(d2, d1, h) - k * h * (1.0 - h); 18 | } 19 | 20 | float opSmoothSubtraction(float d1, float d2, float k) { 21 | float h = clamp(0.5 - 0.5 * (d2 + d1) / k, 0.0, 1.0); 22 | return mix(d2, -d1, h) + k * h * (1.0 - h); 23 | } 24 | 25 | float opSmoothIntersection(float d1, float d2, float k) { 26 | float h = clamp(0.5 - 0.5 * (d2 - d1) / k, 0.0, 1.0); 27 | return mix(d2, d1, h) + k * h * (1.0 - h); 28 | } 29 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/CreatureSim/Visual/DefaultCreatureModelHandler.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation.ContinuousSpaceTimeSims.CreatureSim.Visual; 4 | 5 | public class DefaultCreatureModelHandler : ICreatureModelHandler 6 | { 7 | private Node3D _model; 8 | 9 | public DefaultCreatureModelHandler(Node3D model) 10 | { 11 | _model = model; 12 | } 13 | public void OnReady(Node3D nodeCreature) 14 | { 15 | nodeCreature.AddChild(_model); 16 | _model.GetChild(0).SetColorOfAllMaterials(PrimerColor.Blue); 17 | } 18 | 19 | public void Initialize(float normalizedAwareness) {} 20 | public void Update(CreatureComponent creatureComponent) {} 21 | 22 | public void TriggerEatAnimation(float duration) {} 23 | 24 | public Vector3 GetMouthPosition() 25 | { 26 | return _model.Position; 27 | } 28 | } -------------------------------------------------------------------------------- /Utilities/PrimerGD.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks.Dataflow; 3 | using Godot; 4 | 5 | namespace PrimerTools; 6 | 7 | public static class PrimerGD 8 | { 9 | public static void PrintWithStackTrace(params object[] what) 10 | { 11 | GD.Print(AppendStackTrace(what)); 12 | } 13 | public static void PushWarningWithStackTrace(params object[] what) 14 | { 15 | GD.PushWarning(AppendStackTrace(what)); 16 | } 17 | public static void PrintErrorWithStackTrace(params object[] what) 18 | { 19 | GD.PrintErr(AppendStackTrace(what)); 20 | } 21 | 22 | private static object[] AppendStackTrace(params object[] what) 23 | { 24 | var whatWithStackTrace = new object[what.Length + 1]; 25 | what.CopyTo(whatWithStackTrace, 0); 26 | 27 | var stackTrace = new System.Diagnostics.StackTrace(true); 28 | whatWithStackTrace[what.Length] = "\n" + stackTrace; 29 | 30 | return whatWithStackTrace; 31 | } 32 | } -------------------------------------------------------------------------------- /Graph/Scenes/axis_tic_x.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://c57q0rwh3i0n8"] 2 | 3 | [ext_resource type="Script" uid="uid://c7lydnaf1yvd0" path="res://addons/PrimerTools/Graph/Axis/AxisTic.cs" id="1_xex3i"] 4 | [ext_resource type="Script" uid="uid://cmvfwbhqujfxe" path="res://addons/PrimerTools/LaTeX/LatexNode.cs" id="2_lwl1y"] 5 | 6 | [sub_resource type="CylinderMesh" id="CylinderMesh_e2pjk"] 7 | 8 | [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ctxjs"] 9 | 10 | [node name="axis_tic" type="Node3D"] 11 | script = ExtResource("1_xex3i") 12 | 13 | [node name="MeshInstance3D" type="MeshInstance3D" parent="."] 14 | transform = Transform3D(0.038, 0, 0, 0, 0.1, 0, 0, 0, 0.038, 0, 0, 0) 15 | mesh = SubResource("CylinderMesh_e2pjk") 16 | surface_material_override/0 = SubResource("StandardMaterial3D_ctxjs") 17 | 18 | [node name="LatexNode" type="Node3D" parent="."] 19 | transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, -0.14036, 0) 20 | script = ExtResource("2_lwl1y") 21 | latex = "2" 22 | VerticalAlignment = 0 23 | -------------------------------------------------------------------------------- /TestScenes/Graph/TernaryGraphTestSequence.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools; 3 | using PrimerTools.Graph; 4 | 5 | [Tool] 6 | public partial class TernaryGraphTestSequence : AnimationSequence 7 | { 8 | protected override void Define() 9 | { 10 | var ternaryPlot = new TernaryGraphWithBars(); 11 | ternaryPlot.Colors = new[] 12 | { 13 | PrimerColor.Red, 14 | PrimerColor.Blue, 15 | PrimerColor.Yellow 16 | }; 17 | AddChild(ternaryPlot); 18 | ternaryPlot.CreateBounds(); 19 | 20 | RegisterAnimation(ternaryPlot.ScaleToAnimation(1)); 21 | 22 | ternaryPlot.BarsPerSide = 11; 23 | 24 | var numBars = ternaryPlot.BarsPerSide * (ternaryPlot.BarsPerSide + 1) / 2; 25 | var data = new float[numBars]; 26 | var rng = new System.Random(System.Environment.TickCount); 27 | for (var i = 0; i < numBars; i++) 28 | { 29 | data[i] = (float)rng.NextDouble(); 30 | } 31 | 32 | ternaryPlot.Data = data; 33 | 34 | ternaryPlot.AddBars(); 35 | ternaryPlot.MakeSelfAndChildrenLocal(GetTree().EditedSceneRoot); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LaTeX/TEXTURE_RENDERING_ALTERNATIVE.md: -------------------------------------------------------------------------------- 1 | # Alternative LaTeX Rendering Using Textures 2 | 3 | ## Overview 4 | This document outlines an alternative approach to rendering LaTeX in Godot using textures on plane meshes instead of the expensive Blender pipeline for converting SVG to 3D meshes. This approach could be 10-100x faster while still supporting per-character animations. 5 | 6 | ## Current Pipeline Issues 7 | - Blender processing is expensive (slow) 8 | - Requires external Blender installation 9 | - Complex pipeline with multiple conversion steps 10 | - Resource intensive for many LaTeX expressions 11 | 12 | ## Proposed Solution: SVG to Texture Rendering 13 | 14 | ### Basic Approach 15 | 1. Keep existing LaTeX → SVG conversion (using xelatex and dvisvgm) 16 | 2. Rasterize SVG to high-quality texture instead of converting to 3D mesh 17 | 3. Apply texture to plane mesh(es) in Godot 18 | 4. For per-character animations, use separate planes for each character 19 | 20 | ### Implementation Options 21 | 22 | #### Option 1: Single Texture on Single Plane (Simplest) 23 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/TreeSim/Visual/TreeVisualEventManager.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools.Simulation; 3 | using PrimerTools.Simulation.Components; 4 | using PrimerTools.Simulation.Visual; 5 | 6 | namespace GladiatorManager.ContinuousSpaceTimeSims.CreatureSim.Visual; 7 | 8 | public class TreeVisualEventManager : IVisualEventManager 9 | { 10 | private readonly VisualEntityRegistry _visualRegistry; 11 | 12 | public TreeVisualEventManager(VisualEntityRegistry visualRegistry) 13 | { 14 | _visualRegistry = visualRegistry; 15 | _visualRegistry.RegisterEntityType(); 16 | _visualRegistry.SubscribeToComponentEvents(); 17 | 18 | TreeSystem.TreeDeathEvent += OnTreeDeath; 19 | } 20 | 21 | private void OnTreeDeath(EntityId entityId) 22 | { 23 | _visualRegistry.GetVisualEntity(entityId).Death(); 24 | } 25 | 26 | public void Cleanup() 27 | { 28 | TreeSystem.TreeDeathEvent -= OnTreeDeath; 29 | } 30 | } -------------------------------------------------------------------------------- /Graph/Scenes/axis_tic_y.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://salehjyt5hwh"] 2 | 3 | [ext_resource type="Script" uid="uid://c7lydnaf1yvd0" path="res://addons/PrimerTools/Graph/Axis/AxisTic.cs" id="1_xtd3d"] 4 | [ext_resource type="Script" uid="uid://cmvfwbhqujfxe" path="res://addons/PrimerTools/LaTeX/LatexNode.cs" id="2_ecvgd"] 5 | 6 | [sub_resource type="CylinderMesh" id="CylinderMesh_31fei"] 7 | 8 | [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_wh18w"] 9 | 10 | [node name="axis_tic" type="Node3D"] 11 | script = ExtResource("1_xtd3d") 12 | 13 | [node name="MeshInstance3D" type="MeshInstance3D" parent="."] 14 | transform = Transform3D(0.038, 0, 0, 0, 0.1, 0, 0, 0, 0.038, 0, 0, 0) 15 | mesh = SubResource("CylinderMesh_31fei") 16 | surface_material_override/0 = SubResource("StandardMaterial3D_wh18w") 17 | 18 | [node name="LatexNode" type="Node3D" parent="."] 19 | transform = Transform3D(-8.74228e-09, 0.2, 0, -0.2, -8.74228e-09, 0, 0, 0, 0.2, 1.81738e-08, 0.151382, 0) 20 | script = ExtResource("2_ecvgd") 21 | latex = "11112" 22 | HorizontalAlignment = 2 23 | -------------------------------------------------------------------------------- /Utilities/Pool.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | 4 | namespace PrimerTools; 5 | 6 | public class Pool : Stack where T : Node3D, new() 7 | { 8 | private readonly PackedScene scene; 9 | public Pool(PackedScene scene = null, int initialSize = 1) 10 | { 11 | this.scene = scene; 12 | 13 | for (var i = 0; i < initialSize; i++) 14 | { 15 | NewPooledObject(); 16 | } 17 | } 18 | public void ReturnToPool(T node, bool makeInvisible = true, bool unparent = true) 19 | { 20 | if (makeInvisible) { node.Visible = false; } 21 | if (unparent) { node.SetParent(null); } 22 | Push(node); 23 | } 24 | 25 | private T NewPooledObject() 26 | { 27 | if (scene == null) 28 | { 29 | return new T(); 30 | } 31 | return (T)scene.Instantiate(); 32 | } 33 | 34 | public T GetFromPool() 35 | { 36 | var pooledNode = Count > 0 ? Pop() : NewPooledObject(); 37 | pooledNode.Visible = true; 38 | return pooledNode; 39 | } 40 | } -------------------------------------------------------------------------------- /Simulation/DataVisualization/PeriodicPlotter.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Godot; 3 | using PrimerTools.Graph; 4 | 5 | public partial class PeriodicPlotter : Node 6 | { 7 | public Graph graph; 8 | 9 | [Export] public bool Plotting; 10 | [Export] public double PlottingInterval = 1; 11 | private double _timeSinceLastPlot; 12 | public override void _Process(double delta) 13 | { 14 | if (!Plotting) return; 15 | _timeSinceLastPlot += delta; 16 | if (_timeSinceLastPlot < PlottingInterval) return; 17 | PlotData(); 18 | _timeSinceLastPlot -= PlottingInterval; 19 | } 20 | 21 | private void PlotData(double duration = -1) 22 | { 23 | if (duration < 0) duration = PlottingInterval; 24 | foreach (var dataPlotter in graph.GetChildren().OfType()) 25 | { 26 | dataPlotter.FetchData(); 27 | dataPlotter.TweenTransition(duration); 28 | } 29 | } 30 | 31 | public void PlotNow(double duration = -1) 32 | { 33 | PlotData(duration); 34 | _timeSinceLastPlot = 0; 35 | } 36 | } -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/TreeSim/Components/TreeComponent.cs: -------------------------------------------------------------------------------- 1 | namespace PrimerTools.Simulation.Components; 2 | 3 | public struct TreeComponent : IComponent 4 | { 5 | public EntityId EntityId { get; set; } 6 | 7 | public float Age; 8 | public bool IsMature => Age >= FruitTreeSimSettings.TreeMaturationTime; 9 | public float TimeSinceLastSpawn; 10 | public bool Alive { get; set; } 11 | 12 | // Fruit tracking 13 | public float TimeSinceLastFruitCheck; 14 | public EntityId[] AttachedFruits; 15 | 16 | // Legacy fruit properties (to be removed after full transition) 17 | public bool HasFruit; 18 | public float FruitGrowthProgress; 19 | 20 | public BodyHandler Body; 21 | 22 | public TreeComponent() // TODO: Add number of flowers as a parameter here 23 | { 24 | Alive = true; 25 | AttachedFruits = new EntityId[FruitTreeSimSettings.MaxFruitsPerTree]; 26 | for (var i = 0; i < AttachedFruits.Length; i++) 27 | { 28 | AttachedFruits[i] = new EntityId(); 29 | } 30 | } 31 | 32 | public void CleanUp() {} 33 | } 34 | -------------------------------------------------------------------------------- /Simulation/Models/Mango/mango_shape_simplified.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ConvexPolygonShape3D" format=3 uid="uid://7oit85ate30t"] 2 | 3 | [resource] 4 | points = PackedVector3Array(0.383126, 0.113117, -0.137998, -0.3862, -0.18043, -0.0265405, -0.386371, -0.166505, -0.0545895, 0.0338802, 0.407276, 0.0952652, 0.102908, -0.122085, 0.27532, 0.105296, -0.448215, -0.153173, -0.0622911, 0.0844141, -0.34465, -0.281847, 0.152606, 0.13841, 0.367449, 0.0153822, 0.125947, -0.228763, -0.317137, 0.139728, -0.172766, -0.371516, -0.233812, -0.268709, 0.208126, -0.122975, 0.187877, 0.0713141, -0.346876, 0.0206848, 0.127105, 0.308001, 0.132228, 0.322023, -0.207564, 0.285597, 0.280449, 0.0848647, 0.229126, -0.331797, -0.207134, 0.130744, -0.370202, 0.0559803, -0.228153, -0.0674634, 0.249922, -0.242101, -0.0123703, -0.28933, -0.04875, -0.234752, -0.332644, -0.189348, -0.446596, -0.0265405, 0.352492, -0.164318, 0.0148451, 0.228028, 0.153509, 0.249964, -0.102876, 0.289386, -0.191185, -0.0347862, -0.428879, 0.070553, 0.271042, 0.279786, -0.17953, 0.324367, -0.0950913, -0.233624, 0.280515, -0.0944793, 0.1924, -0.131639, 0.18159, 0.250447, -0.369455, -0.02615, 0.0848624, -0.0762792, -0.150775, 0.278421) 5 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/TreeSim/Components/FruitComponent.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation.Components; 4 | 5 | public struct FruitComponent : IComponent 6 | { 7 | public EntityId EntityId { get; set; } 8 | 9 | // Parent tree reference 10 | public EntityId ParentTreeId; 11 | public int PositionIndex; // Which position on the tree 12 | 13 | // Growth and lifecycle 14 | // public float Age; 15 | public float GrowthProgress; // 0-1 scale 16 | // public bool IsRipe => GrowthProgress >= 1.0f; 17 | public bool IsAttached; // Whether still attached to tree 18 | public float DetachedTime; // How long since it fell from tree 19 | 20 | // Physics 21 | public BodyHandler Body; 22 | 23 | public FruitComponent(EntityId parentTreeId, int positionIndex) 24 | { 25 | ParentTreeId = parentTreeId; 26 | PositionIndex = positionIndex; 27 | // Age = 0; 28 | // GrowthProgress = 0; 29 | IsAttached = true; 30 | DetachedTime = 0; 31 | } 32 | 33 | public void CleanUp() 34 | { 35 | Body.CleanUp(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Utilities/Vector3Utilities.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Utilities; 4 | 5 | public static class VectorUtilities 6 | { 7 | public static Vector2 RandomVector2(Vector2 min, Vector2 max, Rng rng = null) 8 | { 9 | return new Vector2( 10 | rng.RangeFloat(min.X, max.X), 11 | rng.RangeFloat(min.Y, max.Y) 12 | ); 13 | } 14 | 15 | public static Vector3 RandomVector3(Vector3 min, Vector3 max, Rng rng = null) 16 | { 17 | return new Vector3( 18 | rng.RangeFloat(min.X, max.X), 19 | rng.RangeFloat(min.Y, max.Y), 20 | rng.RangeFloat(min.Z, max.Z) 21 | ); 22 | } 23 | 24 | public static Vector3 RandomXYZEulerRotationVector(Rng rng = null) 25 | { 26 | var x = rng.RangeFloat(-1, 1); 27 | x = Mathf.Asin(x); 28 | var y = rng.RangeFloat(0, Mathf.Pi * 2); 29 | var z = rng.RangeFloat(0, Mathf.Pi * 2); 30 | 31 | return new Vector3(x, y, z); 32 | } 33 | 34 | public static Vector3 RandomlyRotatedUnitVector(Rng rng = null) 35 | { 36 | return Quaternion.FromEuler(RandomXYZEulerRotationVector(rng)) * Vector3.Forward; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /Graph/DataObjects/CurvePlot2D/CurvePlot2DUtilities.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Godot; 5 | 6 | namespace PrimerTools.Graph; 7 | 8 | public static class CurvePlot2DUtilities 9 | { 10 | // TODO: Could make these instance methods since they need a curve? 11 | public static CurvePlot2D.DataFetch AppendCount(Func> dataSourceGetter, CurvePlot2D curve) 12 | { 13 | return () => 14 | { 15 | var dataList = curve.GetData().ToList(); 16 | var collection = dataSourceGetter().ToArray(); 17 | dataList.Add(new Vector3(dataList.Count, collection.Length, 0)); 18 | return dataList; 19 | }; 20 | } 21 | 22 | public static CurvePlot2D.DataFetch AppendAverageProperty( 23 | Func> dataSourceGetter, 24 | CurvePlot2D curve, 25 | Func propertySelector 26 | ) 27 | { 28 | return () => 29 | { 30 | var dataList = curve.GetData().ToList(); 31 | dataList.Add(new Vector3(dataList.Count, dataSourceGetter().Average(propertySelector), 0)); 32 | return dataList; 33 | }; 34 | } 35 | } -------------------------------------------------------------------------------- /Graph/DataObjects/SurfacePlot/SurfacePlot_Height.gdshader: -------------------------------------------------------------------------------- 1 | // res://shaders/SurfacePlot_Height.gdshader 2 | shader_type spatial; 3 | render_mode cull_disabled; 4 | 5 | uniform sampler2D height_tex_a : source_color; 6 | uniform sampler2D height_tex_b : source_color; 7 | uniform float mix_factor : hint_range(0,1) = 0.0; 8 | uniform float cutoff : hint_range(0,1) = 1.0; 9 | 10 | uniform vec2 x_range = vec2(0.0, 1.0); 11 | uniform vec2 z_range = vec2(0.0, 1.0); 12 | uniform vec3 pos_scale = vec3(1.0); 13 | uniform vec3 pos_offset = vec3(0.0); 14 | 15 | uniform vec4 albedo_color : source_color = vec4(1.0); 16 | 17 | float sample_height(vec2 uv) { 18 | float ha = texture(height_tex_a, uv).r; 19 | float hb = texture(height_tex_b, uv).r; 20 | return mix(ha, hb, mix_factor); 21 | } 22 | 23 | void vertex() { 24 | // Map UV → data space 25 | float x_ds = mix(x_range.x, x_range.y, UV.x); 26 | float z_ds = mix(z_range.x, z_range.y, UV.y); 27 | float y_ds = sample_height(UV); 28 | 29 | vec3 pos = vec3(x_ds, y_ds, z_ds); 30 | VERTEX = pos * pos_scale + pos_offset; 31 | } 32 | 33 | void fragment() { 34 | if (UV.x > cutoff) { discard; } 35 | ALBEDO = albedo_color.rgb; 36 | ALPHA = albedo_color.a; 37 | } 38 | -------------------------------------------------------------------------------- /2D/Diagram/DiagramSystem.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools; 3 | using PrimerTools._2D.Diagram; 4 | 5 | // [Tool] 6 | public partial class DiagramSystem : Node 7 | { 8 | public ShapeStyle DefaultStyle { get; set; } = new ShapeStyle(); 9 | 10 | public DiagramSystem() {} 11 | 12 | // [ExportToolButton("Create")] 13 | // private Callable Create => Callable.From(RebuildDiagram); 14 | 15 | protected virtual void DefineDiagram() {} 16 | 17 | public void AddElement(DiagramElement element) 18 | { 19 | if (element.Style == null) 20 | { 21 | element.Style = DefaultStyle.Clone(); 22 | } 23 | 24 | element.CreateMesh(this); 25 | } 26 | 27 | public void RebuildDiagram() 28 | { 29 | // Clear existing meshes 30 | foreach (var child in GetChildren()) 31 | { 32 | if (Engine.IsEditorHint()) 33 | { 34 | child.Free(); 35 | } 36 | else 37 | { 38 | child.QueueFree(); 39 | } 40 | } 41 | 42 | DefineDiagram(); 43 | BuildDiagram(); 44 | 45 | if (Engine.IsEditorHint()) this.MakeSelfAndChildrenLocal(); 46 | } 47 | 48 | public void BuildDiagram() {} 49 | } 50 | -------------------------------------------------------------------------------- /Gestures/Tests/BracketTestScene.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools; 3 | 4 | [Tool] 5 | public partial class BracketTestScene : AnimationSequence 6 | { 7 | 8 | private void CallTweenTransition(Bracket bracket, double duration) 9 | { 10 | bracket.TweenTransition(duration); 11 | } 12 | 13 | protected override void Define() 14 | { 15 | var bracket = Bracket.CreateInstance(); 16 | AddChild(bracket); 17 | 18 | bracket.LeftTipPosition = new Vector3(-7, 0, 1); 19 | bracket.RightTipPosition = new Vector3(7, 0, 3); 20 | RegisterAnimation(bracket.Transition()); 21 | 22 | bracket.LeftTipPosition = new Vector3(-7, 5, 1); 23 | bracket.RightTipPosition = new Vector3(7, -5, 3); 24 | RegisterAnimation(bracket.Transition()); 25 | 26 | bracket.LeftTipPosition = new Vector3(7, 5, 1); 27 | bracket.RightTipPosition = new Vector3(-7, -5, 3); 28 | RegisterAnimation(bracket.Transition()); 29 | 30 | bracket.LeftTipPosition = new Vector3(7, 5, -1); 31 | bracket.RightTipPosition = new Vector3(-7, -5, -3); 32 | RegisterAnimation(bracket.Transition()); 33 | 34 | bracket.LeftTipPosition = new Vector3(1, 0, 1); 35 | bracket.RightTipPosition = new Vector3(-1, 0, 1); 36 | RegisterAnimation(this.MethodCall("CallTweenTransition", new Godot.Collections.Array() {bracket, 2})); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Entities/EntityId.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Godot; 3 | 4 | namespace PrimerTools.Simulation; 5 | 6 | public readonly struct EntityId : IEquatable 7 | { 8 | // This is all for type safety 9 | public readonly uint Value = 0; 10 | 11 | public EntityId(uint value) 12 | { 13 | Value = value; 14 | } 15 | 16 | public override string ToString() 17 | { 18 | return Value.ToString(); 19 | } 20 | 21 | public bool IsValid => Value > 0; 22 | 23 | public bool Equals(EntityId other) 24 | { 25 | return Value == other.Value; 26 | } 27 | 28 | public override bool Equals(object obj) 29 | { 30 | return obj is EntityId other && Equals(other); 31 | } 32 | 33 | public override int GetHashCode() 34 | { 35 | // To my knowledge, this is deterministic and should be fine. 36 | // But probably Value will never get big enough to test it anyway. 37 | return (int)Value; 38 | } 39 | 40 | public static bool operator ==(EntityId left, EntityId right) 41 | { 42 | return left.Equals(right); 43 | } 44 | 45 | public static bool operator !=(EntityId left, EntityId right) 46 | { 47 | return !left.Equals(right); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Utilities/PrimerMathUtils.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools; 4 | 5 | public static class PrimerMathUtils 6 | { 7 | public static double DecayingExponentialWithMin(double initialDuration, double decayFactor, double minDuration, double step) 8 | { 9 | // TODO: Could fit this to an actual exponential instead of clamping, but who cares 10 | return Mathf.Max(initialDuration * Mathf.Pow(decayFactor, step), minDuration); 11 | } 12 | 13 | public static Vector3 SlerpThatWorks(Vector3 from, Vector3 to, float weight) 14 | { 15 | float s1 = from.Length(); 16 | float s2 = to.Length(); 17 | if (s1 == 0.0 || s2 == 0.0) 18 | return from.Lerp(to, weight); 19 | float num1 = Mathf.Lerp(s1, s2, weight); 20 | float angle = from.AngleTo(to); 21 | if (angle == 0.0) 22 | return from.Lerp(to, weight); 23 | Vector3 axis = from.Cross(to).Normalized(); 24 | if (axis.Length() == 0) 25 | { 26 | // GD.Print($"Vectors that cross to zero: {from}, {to}"); 27 | return from.Lerp(to, weight); 28 | } 29 | return from.Rotated(axis, angle * weight) * (num1 / s1); 30 | } 31 | 32 | public static double Sigmoid(double x) 33 | { 34 | return 1.0 / (1.0 + Mathf.Exp(-x)); 35 | } 36 | } -------------------------------------------------------------------------------- /StateChangeAnimationSystem/MethodTriggerStateChange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Godot; 3 | 4 | public class MethodTriggerStateChange : IAnimatedStateChange 5 | { 6 | private readonly Action _callback; 7 | private readonly string _name; 8 | private bool _hasTriggered = false; 9 | 10 | public string Name => _name; 11 | public double Duration => 0; // Instant trigger 12 | 13 | public MethodTriggerStateChange(Action callback, string name = null) 14 | { 15 | _callback = callback ?? throw new ArgumentNullException(nameof(callback)); 16 | _name = name ?? "MethodTrigger"; 17 | } 18 | 19 | public void SetTriggered() 20 | { 21 | _hasTriggered = true; 22 | } 23 | public void Execute() 24 | { 25 | if (_hasTriggered) return; 26 | _callback.Invoke(); 27 | _hasTriggered = true; 28 | } 29 | 30 | public IStateChange WithDuration(double duration) 31 | { 32 | // Method triggers are instant 33 | return this; 34 | } 35 | 36 | // Seeking-related methods are empty. 37 | // See TODO in IAnimatedStateChange 38 | public void EvaluateAtTime(double elapsedTime) {} 39 | 40 | public void ApplyEndState() {} 41 | 42 | public void RecordStartState() {} 43 | 44 | public void Revert() 45 | { 46 | _hasTriggered = false; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /Graph/Scenes/axis.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://dw3ic4fy1t6jc"] 2 | 3 | [ext_resource type="PackedScene" uid="uid://d1y06ar34m5qm" path="res://addons/PrimerTools/Graph/Scenes/graph_arrow_head.tscn" id="1_1vsiv"] 4 | [ext_resource type="Script" uid="uid://cm3l3own6skv3" path="res://addons/PrimerTools/Graph/Axis/Axis.cs" id="1_gobhs"] 5 | 6 | [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ntcfd"] 7 | 8 | [sub_resource type="CylinderMesh" id="CylinderMesh_gedf0"] 9 | material = SubResource("StandardMaterial3D_ntcfd") 10 | height = 1.0 11 | 12 | [node name="Axis" type="Node3D"] 13 | script = ExtResource("1_gobhs") 14 | Length = 3.0 15 | Chonk = 1.83 16 | 17 | [node name="Rod" type="Node3D" parent="."] 18 | transform = Transform3D(3, 0, 0, 0, 1, 0, 0, 0, 1, -0.2, 0, 0) 19 | 20 | [node name="RodMesh" type="MeshInstance3D" parent="Rod"] 21 | transform = Transform3D(-1.74846e-09, 1, -1.18109e-17, -0.0399939, -4.37047e-08, -0.000698097, -0.000698097, -7.62869e-10, 0.0399939, 0.5, 0, 0) 22 | mesh = SubResource("CylinderMesh_gedf0") 23 | 24 | [node name="Head" parent="." instance=ExtResource("1_1vsiv")] 25 | transform = Transform3D(-3.0598e-09, 0.07, 0, -0.07, -3.0598e-09, 0, 0, 0, 0.07, 2.8, 0, 0) 26 | 27 | [node name="Tail" parent="." instance=ExtResource("1_1vsiv")] 28 | transform = Transform3D(-3.0598e-09, -0.07, 0, 0.07, -3.0598e-09, 0, 0, 0, 0.07, -0.2, 0, 0) 29 | -------------------------------------------------------------------------------- /Gestures/Arrow/arrow.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://tug6o7ke0tmd"] 2 | 3 | [ext_resource type="Script" uid="uid://buxdena8nbmvj" path="res://addons/PrimerTools/Gestures/Arrow/Arrow.cs" id="1_j1bvc"] 4 | [ext_resource type="PackedScene" uid="uid://b5orfxct60gxc" path="res://addons/PrimerTools/Gestures/Arrow/arrow_head.blend" id="2_vd7g4"] 5 | [ext_resource type="PackedScene" uid="uid://cwg812eome4k" path="res://addons/PrimerTools/Gestures/Arrow/arrow_shaft.blend" id="3_ojc82"] 6 | 7 | [node name="arrow" type="Node3D" node_paths=PackedStringArray("shaftObject", "headObject", "tailObject")] 8 | transform = Transform3D(0.72463, -0.689138, 0, 0.689138, 0.72463, 0, 0, 0, 1, 0, 0, 0) 9 | script = ExtResource("1_j1bvc") 10 | ShowHeadArrow = true 11 | Chonk = 1.0 12 | Length = 1.69052 13 | XYPlaneRotation = 43.5619 14 | tailPoint = Vector3(1.225, 1.165, 0) 15 | shaftObject = NodePath("shaft") 16 | headObject = NodePath("head") 17 | tailObject = NodePath("tail") 18 | 19 | [node name="head" parent="." instance=ExtResource("2_vd7g4")] 20 | transform = Transform3D(-1, 1.50996e-07, 0, -1.50996e-07, -1, 0, 0, 0, 1, 0, 0, 0) 21 | 22 | [node name="shaft" parent="." instance=ExtResource("3_ojc82")] 23 | transform = Transform3D(1.64052, 0, 0, 0, 1, 0, 0, 0, 1, 0.05, 0, 0) 24 | 25 | [node name="tail" parent="." instance=ExtResource("2_vd7g4")] 26 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.511, 0, 0) 27 | visible = false 28 | -------------------------------------------------------------------------------- /Environment/boilerplate.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://dqncverqnh4kn"] 2 | 3 | [ext_resource type="Script" uid="uid://cmyih6anxr6g7" path="res://addons/PrimerTools/Camera/CameraRig.cs" id="1_tea2c"] 4 | [ext_resource type="Script" uid="uid://b574a0jrxvcix" path="res://addons/PrimerTools/Utilities/FPSViewer.cs" id="2_y5nfq"] 5 | [ext_resource type="Environment" uid="uid://xpav3hoy6ldu" path="res://addons/PrimerTools/Environment/primer_environment.tres" id="3_mfiyt"] 6 | 7 | [node name="Boilerplate" type="Node3D"] 8 | 9 | [node name="CameraRig" type="Node3D" parent="."] 10 | transform = Transform3D(1, 0, 0, 0, 0.956305, 0.292372, 0, -0.292372, 0.956305, 0, 0, 0) 11 | script = ExtResource("1_tea2c") 12 | Distance = 10.0 13 | 14 | [node name="Camera3D" type="Camera3D" parent="CameraRig"] 15 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 24.775) 16 | fov = 30.0 17 | 18 | [node name="Label" type="Label" parent="CameraRig"] 19 | anchors_preset = 1 20 | anchor_left = 1.0 21 | anchor_right = 1.0 22 | offset_left = -59.0 23 | offset_bottom = 23.0 24 | grow_horizontal = 0 25 | text = "142 FPS" 26 | script = ExtResource("2_y5nfq") 27 | 28 | [node name="WorldEnvironment" type="WorldEnvironment" parent="."] 29 | environment = ExtResource("3_mfiyt") 30 | 31 | [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] 32 | transform = Transform3D(1, 0, 0, 0, 0.588477, 0.808514, 0, -0.808514, 0.588477, 0, 5.55125, 8.78822) 33 | shadow_enabled = true 34 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/CreatureSim/Components/CreatureComponent.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation.ContinuousSpaceTimeSims.CreatureSim; 4 | 5 | public struct CreatureComponent : IComponent 6 | { 7 | public EntityId EntityId { get; set; } 8 | public void CleanUp() {} 9 | 10 | public Vector3 CurrentDestination; 11 | public Genome Genome; 12 | public float Age; 13 | public bool ForcedMature; 14 | public float Energy; 15 | public float Digesting; 16 | public float HungerThreshold; 17 | public float EatingTimeLeft; 18 | public float MatingTimeLeft; 19 | public bool Alive; 20 | 21 | public CreatureComponent(Genome genome) : this() 22 | { 23 | Alive = true; 24 | Energy = 1f; 25 | HungerThreshold = CreatureSimSettings.Instance.HungerThreshold; 26 | Genome = genome; 27 | CurrentDestination = Vector3.Zero; 28 | } 29 | 30 | public float MaxSpeed => Genome.GetTrait("MaxSpeed").ExpressedValue; 31 | public float AdjustedSpeed 32 | { 33 | get 34 | { 35 | var antagonisticPleiotropy = Genome.GetTrait("Antagonistic Pleiotropy Speed"); 36 | var factor = 1f; 37 | if (antagonisticPleiotropy is { ExpressedValue: true }) factor = 2f; 38 | return MaxSpeed * factor; 39 | } 40 | } 41 | 42 | public float AwarenessRadius => Genome.GetTrait("AwarenessRadius").ExpressedValue; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Graph/Resources/TernaryPlot.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &6753575479206427162 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 8753566071744205921} 12 | - component: {fileID: 5852832432714851265} 13 | m_Layer: 0 14 | m_Name: TernaryPlot 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &8753566071744205921 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 6753575479206427162} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_ConstrainProportionsScale: 0 31 | m_Children: [] 32 | m_Father: {fileID: 0} 33 | m_RootOrder: 0 34 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 35 | --- !u!114 &5852832432714851265 36 | MonoBehaviour: 37 | m_ObjectHideFlags: 0 38 | m_CorrespondingSourceObject: {fileID: 0} 39 | m_PrefabInstance: {fileID: 0} 40 | m_PrefabAsset: {fileID: 0} 41 | m_GameObject: {fileID: 6753575479206427162} 42 | m_Enabled: 1 43 | m_EditorHideFlags: 0 44 | m_Script: {fileID: 11500000, guid: 20fc66b1c5d0f48a99a8d807d4cc01e0, type: 3} 45 | m_Name: 46 | m_EditorClassIdentifier: 47 | -------------------------------------------------------------------------------- /2D/Diagram/ShapeShaders/line_shader.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | render_mode cull_disabled; 3 | 4 | #include "sdf_primitives.gdshaderinc" 5 | #include "sdf_common.gdshaderinc" 6 | 7 | uniform vec4 shape_color : source_color = vec4(1.0, 0.5, 0.0, 1.0); 8 | uniform vec4 background_color : source_color = vec4(0.0, 0.0, 0.0, 0.0); 9 | uniform float thickness : hint_range(0.01, 0.5) = 0.1; 10 | uniform float smoothness : hint_range(0.001, 0.1) = 0.01; 11 | 12 | // Shape-specific parameters 13 | uniform vec2 point_a = vec2(-1.0, 0.0); 14 | uniform vec2 point_b = vec2(1.0, 0.0); 15 | 16 | varying vec2 object_pos; 17 | 18 | void vertex() { 19 | // Pass object-space position to fragment shader 20 | object_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xy; 21 | } 22 | 23 | void fragment() { 24 | // Use object-space coordinates 25 | vec2 p = object_pos; 26 | 27 | float d = sdLine(p, point_a, point_b); 28 | d = d - thickness; 29 | 30 | float d_dx = dFdx(d); 31 | float d_dy = dFdy(d); 32 | float grad_len = length(vec2(d_dx, d_dy)); 33 | 34 | // Normalize the gradient to get consistent AA width 35 | float aa_width = smoothness * max(grad_len, 0.0001); 36 | 37 | // Apply smoothstep with gradient-based anti-aliasing 38 | float alpha = 1.0 - smoothstep(0.0, aa_width, d); 39 | 40 | // Mix colors based on the SDF 41 | vec3 color = mix(background_color.rgb, shape_color.rgb, alpha); 42 | float final_alpha = mix(background_color.a, shape_color.a, alpha); 43 | 44 | ALBEDO = color; 45 | ALPHA = final_alpha; 46 | } 47 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/CollisionRegistry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Godot; 4 | 5 | namespace PrimerTools.Simulation; 6 | 7 | /// 8 | /// Manages a dictionary storing the IDataEntity type and entityId corresponding to an area Rid in the physics system 9 | /// This allows entities to use area overlap queries to figure out which entities are nearby 10 | /// 11 | public static class CollisionRegistry 12 | { 13 | private static readonly Dictionary GlobalBodyLookup = new(); 14 | 15 | public static void RegisterBody(Rid rid, Type entityType, EntityId entityId) 16 | { 17 | GlobalBodyLookup[rid] = (entityType, entityId.Value); 18 | } 19 | 20 | // Keep the old method for compatibility with existing simulations 21 | public static void RegisterBody(Rid rid, Type entityType, uint entityId) 22 | { 23 | GlobalBodyLookup[rid] = (entityType, entityId); 24 | } 25 | 26 | public static void UnregisterBody(Rid rid) 27 | { 28 | GlobalBodyLookup.Remove(rid); 29 | } 30 | 31 | // New method that returns EntityId 32 | public static bool TryGetEntityInfo(Rid rid, out Type type, out EntityId entityId) 33 | { 34 | if (GlobalBodyLookup.TryGetValue(rid, out var info)) 35 | { 36 | type = info.type; 37 | entityId = new EntityId(info.entityId); 38 | return true; 39 | } 40 | type = null; 41 | entityId = default; 42 | return false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Graph/FromUnity/TernaryPlot/TernaryPointTester.cs: -------------------------------------------------------------------------------- 1 | // using Sirenix.OdinInspector; 2 | // using UnityEngine; 3 | // using UnityEngine.Serialization; 4 | // 5 | // namespace Primer.Graph 6 | // { 7 | // [RequireComponent(typeof(TernaryPlot))] 8 | // public class TernaryPointTester : MonoBehaviour 9 | // { 10 | // [FormerlySerializedAs("startOnValueChange")] 11 | // public bool liveUpdate = false; 12 | // public int automaticPointIncrements = 3; 13 | // public float sphereSize = 1; 14 | // 15 | // public void OnValidate() 16 | // { 17 | // if (liveUpdate) 18 | // PlotPoints(); 19 | // } 20 | // 21 | // [Button] 22 | // private void PlotPoints() 23 | // { 24 | // var ternaryPlot = GetComponent(); 25 | // var gnome = ternaryPlot.GetContentGnome("Points"); 26 | // 27 | // var points = ternaryPlot.isQuaternary 28 | // ? TernaryPlotUtility.EvenlyDistributedPoints3D(automaticPointIncrements) 29 | // : TernaryPlotUtility.EvenlyDistributedPoints(automaticPointIncrements); 30 | // 31 | // foreach (var point in points) { 32 | // var sphere = gnome.AddPrimitive(PrimitiveType.Sphere); 33 | // sphere.localScale = Vector3.one * sphereSize / 10; // Arbitrary, but 1 is way too big 34 | // sphere.localPosition = ternaryPlot.CoordinatesToLocalPosition(point); 35 | // } 36 | // 37 | // gnome.Purge(defer: true); 38 | // } 39 | // } 40 | // } 41 | -------------------------------------------------------------------------------- /StateChangeAnimationSystem/TestStateChangeSequence.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools; 3 | 4 | namespace PrimerTools.TweenSystem; 5 | 6 | public partial class TestStateChangeSequence : StateChangeSequence 7 | { 8 | public override void Define() 9 | { 10 | var cube = new MeshInstance3D(); 11 | cube.Mesh = new BoxMesh(); 12 | AddChild(cube); 13 | 14 | var sphere = new MeshInstance3D(); 15 | sphere.Mesh = new SphereMesh(); 16 | AddChild(sphere); 17 | 18 | AddStateChangeWithDelay(cube.WalkTo(new Vector3(100, 0, 0)).WithDuration(1)); 19 | AddStateChangeWithDelay(sphere.MoveTo(new Vector3(100, 50, 0)).WithDuration(1)); 20 | AddStateChangeWithDelay(cube.WalkTo(new Vector3(0, 50, 0)).WithDuration(2)); 21 | AddStateChangeInParallel(sphere.MoveTo(new Vector3(50, 25, 0)).WithDuration(1), delay: 1); 22 | 23 | // Test rotation 24 | AddStateChangeWithDelay(cube.RotateTo(0, 90, 0).WithDuration(1)); 25 | 26 | // Test WalkTo (combines rotation and movement) 27 | AddStateChangeWithDelay(cube.WalkTo(new Vector3(50, 0, 0)).WithDuration(2)); 28 | 29 | // Test Pulse 30 | AddStateChangeWithDelay(cube.Pulse(scaleFactor: 1.5f, attack: 0.3, hold: 0.2, decay: 0.3)); 31 | 32 | var composite = new CompositeStateChange(); 33 | composite.AddStateChangeWithDelay(cube.MoveTo(new Vector3(100, 25, 0)).WithDuration(1)); 34 | composite.AddStateChangeInParallel(sphere.MoveTo(new Vector3(100, 25, 0)).WithDuration(1)); 35 | AddStateChangeWithDelay(composite, 1); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /2D/Diagram/ShapeShaders/circle_shader.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | render_mode cull_disabled; 3 | 4 | #include "sdf_primitives.gdshaderinc" 5 | #include "sdf_common.gdshaderinc" 6 | 7 | uniform vec4 shape_color : source_color = vec4(1.0, 0.5, 0.0, 1.0); 8 | uniform vec4 background_color : source_color = vec4(0.0, 0.0, 0.0, 0.0); 9 | uniform float thickness : hint_range(0.01, 0.5) = 0.1; 10 | uniform float inner_thickness : hint_range(0.01, 0.5) = 0.01; 11 | uniform float smoothness : hint_range(0.001, 0.1) = 0.01; 12 | 13 | // Shape-specific parameters 14 | uniform vec2 shape_center = vec2(0.0, 0.0); // Center in object space 15 | uniform float radius = 1; 16 | 17 | varying vec2 object_pos; 18 | 19 | void vertex() { 20 | // Pass object-space position to fragment shader 21 | object_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xy; 22 | } 23 | 24 | void fragment() { 25 | // Use object-space coordinates instead of UV 26 | vec2 p = object_pos - shape_center; 27 | 28 | float d = sdCircle(p, radius); 29 | d = applyThickness(d, thickness, inner_thickness); 30 | 31 | float d_dx = dFdx(d); 32 | float d_dy = dFdy(d); 33 | float grad_len = length(vec2(d_dx, d_dy)); 34 | 35 | // Normalize the gradient to get consistent AA width 36 | float aa_width = smoothness * max(grad_len, 0.0001); 37 | 38 | // Apply smoothstep with gradient-based anti-aliasing 39 | float alpha = 1.0 - smoothstep(0.0, aa_width, d); 40 | 41 | // Mix colors based on the SDF 42 | vec3 color = mix(background_color.rgb, shape_color.rgb, alpha); 43 | float final_alpha = mix(background_color.a, shape_color.a, alpha); 44 | 45 | ALBEDO = color; 46 | ALPHA = final_alpha; 47 | } 48 | -------------------------------------------------------------------------------- /2D/Diagram/ShapeShaders/triangle_shader.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | render_mode cull_disabled; 3 | 4 | #include "sdf_primitives.gdshaderinc" 5 | #include "sdf_common.gdshaderinc" 6 | 7 | uniform vec4 shape_color : source_color = vec4(1.0, 0.5, 0.0, 1.0); 8 | uniform vec4 background_color : source_color = vec4(0.0, 0.0, 0.0, 0.0); 9 | uniform float thickness : hint_range(0.01, 0.5) = 0.1; 10 | uniform float inner_thickness : hint_range(0.01, 0.5) = 0.01; 11 | uniform float smoothness : hint_range(0.001, 0.1) = 0.01; 12 | 13 | // Shape-specific parameters 14 | uniform vec2 point_a = vec2(0.0, 1.0); 15 | uniform vec2 point_b = vec2(-0.866, -0.5); 16 | uniform vec2 point_c = vec2(0.866, -0.5); 17 | 18 | varying vec2 object_pos; 19 | 20 | void vertex() { 21 | // Pass object-space position to fragment shader 22 | object_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xy; 23 | } 24 | 25 | void fragment() { 26 | // Use object-space coordinates 27 | vec2 p = object_pos; 28 | 29 | float d = sdTriangle(p, point_a, point_b, point_c); 30 | d = applyThickness(d, thickness, inner_thickness); 31 | 32 | float d_dx = dFdx(d); 33 | float d_dy = dFdy(d); 34 | float grad_len = length(vec2(d_dx, d_dy)); 35 | 36 | // Normalize the gradient to get consistent AA width 37 | float aa_width = smoothness * max(grad_len, 0.0001); 38 | 39 | // Apply smoothstep with gradient-based anti-aliasing 40 | float alpha = 1.0 - smoothstep(0.0, aa_width, d); 41 | 42 | // Mix colors based on the SDF 43 | vec3 color = mix(background_color.rgb, shape_color.rgb, alpha); 44 | float final_alpha = mix(background_color.a, shape_color.a, alpha); 45 | 46 | ALBEDO = color; 47 | ALPHA = final_alpha; 48 | } 49 | -------------------------------------------------------------------------------- /2D/Diagram/ShapeShaders/arrow_shader.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | render_mode cull_disabled; 3 | 4 | #include "sdf_primitives.gdshaderinc" 5 | #include "sdf_common.gdshaderinc" 6 | 7 | uniform vec4 shape_color : source_color = vec4(1.0, 0.5, 0.0, 1.0); 8 | uniform vec4 background_color : source_color = vec4(0.0, 0.0, 0.0, 0.0); 9 | uniform float thickness : hint_range(0, 0.5) = 0.1; 10 | uniform float smoothness : hint_range(0, 0.1) = 0.01; 11 | 12 | // Arrow-specific parameters 13 | uniform vec2 arrow_start = vec2(-1.0, 0.0); 14 | uniform vec2 arrow_end = vec2(1.0, 0.0); 15 | uniform float head_length = 0.3; 16 | uniform float head_angle = 30.0; // degrees 17 | 18 | varying vec2 object_pos; 19 | 20 | void vertex() { 21 | // Pass object-space position to fragment shader 22 | object_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xy; 23 | } 24 | 25 | void fragment() { 26 | // Use object-space coordinates 27 | vec2 p = object_pos; 28 | 29 | float d = sdArrow(p, arrow_start, arrow_end, head_length, head_angle); 30 | d = d - thickness; 31 | 32 | float d_dx = dFdx(d); 33 | float d_dy = dFdy(d); 34 | float grad_len = length(vec2(d_dx, d_dy)); 35 | 36 | // Normalize the gradient to get consistent AA width 37 | //float aa_width = smoothness * max(grad_len, 0.0001); 38 | float aa_width = smoothness * grad_len; 39 | 40 | // Apply smoothstep with gradient-based anti-aliasing 41 | float alpha = 1.0 - smoothstep(0.0, aa_width, d); 42 | 43 | // Mix colors based on the SDF 44 | vec3 color = mix(background_color.rgb, shape_color.rgb, alpha); 45 | float final_alpha = mix(background_color.a, shape_color.a, alpha); 46 | 47 | ALBEDO = color; 48 | ALPHA = final_alpha; 49 | } 50 | -------------------------------------------------------------------------------- /2D/Diagram/ShapeShaders/rectangle_shader.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | render_mode cull_disabled; 3 | 4 | #include "sdf_primitives.gdshaderinc" 5 | #include "sdf_common.gdshaderinc" 6 | 7 | uniform vec4 shape_color : source_color = vec4(1.0, 0.5, 0.0, 1.0); 8 | uniform vec4 background_color : source_color = vec4(0.0, 0.0, 0.0, 0.0); 9 | uniform float thickness : hint_range(0.01, 0.5) = 0.1; 10 | uniform float inner_thickness : hint_range(0.01, 0.5) = 0.01; 11 | uniform float smoothness : hint_range(0.001, 0.1) = 0.01; 12 | 13 | // Shape-specific parameters 14 | uniform vec2 shape_center = vec2(0.0, 0.0); // Center in object space 15 | uniform vec2 size = vec2(1.0, 0.5); // Half-width and half-height 16 | 17 | varying vec2 object_pos; 18 | 19 | void vertex() { 20 | // Pass object-space position to fragment shader 21 | object_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xy; 22 | } 23 | 24 | void fragment() { 25 | // Use object-space coordinates instead of UV 26 | vec2 p = object_pos - shape_center; 27 | 28 | float d = sdBox(p, size); 29 | d = applyThickness(d, thickness, inner_thickness); 30 | 31 | float d_dx = dFdx(d); 32 | float d_dy = dFdy(d); 33 | float grad_len = length(vec2(d_dx, d_dy)); 34 | 35 | // Normalize the gradient to get consistent AA width 36 | float aa_width = smoothness * max(grad_len, 0.0001); 37 | 38 | // Apply smoothstep with gradient-based anti-aliasing 39 | float alpha = 1.0 - smoothstep(0.0, aa_width, d); 40 | 41 | // Mix colors based on the SDF 42 | vec3 color = mix(background_color.rgb, shape_color.rgb, alpha); 43 | float final_alpha = mix(background_color.a, shape_color.a, alpha); 44 | 45 | ALBEDO = color; 46 | ALPHA = final_alpha; 47 | } 48 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/CreatureSim/Visual/CreatureVisualEventManager.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools.Simulation; 3 | using PrimerTools.Simulation.ContinuousSpaceTimeSims.CreatureSim; 4 | using PrimerTools.Simulation.ContinuousSpaceTimeSims.CreatureSim.Visual; 5 | using PrimerTools.Simulation.Visual; 6 | 7 | namespace GladiatorManager.ContinuousSpaceTimeSims.CreatureSim.Visual; 8 | 9 | public class CreatureVisualEventManager : IVisualEventManager 10 | { 11 | private readonly VisualEntityRegistry _visualRegistry; 12 | 13 | public CreatureVisualEventManager(VisualEntityRegistry visualRegistry) 14 | { 15 | _visualRegistry = visualRegistry; 16 | _visualRegistry.RegisterEntityType(new DefaultCreatureFactory()); 17 | _visualRegistry.SubscribeToComponentEvents(); 18 | 19 | CreatureSystem.CreatureDeathEvent += OnCreatureDeath; 20 | CreatureSystem.CreatureEatEvent += OnCreatureEat; 21 | } 22 | 23 | private void OnCreatureDeath(EntityId entityId, CreatureSystem.DeathCause cause) 24 | { 25 | _visualRegistry.GetVisualEntity(entityId).HandleDeath(cause); 26 | } 27 | 28 | private void OnCreatureEat(EntityId creatureId, EntityId treeId, float duration) 29 | { 30 | var creature = _visualRegistry.GetVisualEntity(creatureId); 31 | var tree = _visualRegistry.GetVisualEntity(treeId); 32 | creature.HandleEat(tree.GetFruit(), duration); 33 | } 34 | 35 | public void Cleanup() 36 | { 37 | CreatureSystem.CreatureDeathEvent -= OnCreatureDeath; 38 | CreatureSystem.CreatureEatEvent -= OnCreatureEat; 39 | } 40 | } -------------------------------------------------------------------------------- /Utilities/MemoryPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace RockPaperScissors; 5 | 6 | /// 7 | /// A memory pool that can reclaim all borrowed memory at once. 8 | /// 9 | public static class MemoryPool 10 | { 11 | private static readonly Stack> _listPool = new(); 12 | private static readonly Dictionary> _arrayPool = new(); 13 | 14 | private static readonly List> _borrowedLists = new(); 15 | private static readonly List _borrowedArrays = new(); 16 | 17 | public static List BorrowList() 18 | { 19 | if (!_listPool.TryPop(out var list)) 20 | list = new List(); 21 | _borrowedLists.Add(list); 22 | return list; 23 | } 24 | 25 | public static T[] BorrowArray(int length) 26 | { 27 | if (!_arrayPool.TryGetValue(length, out var stack)) 28 | { 29 | stack = new Stack(); 30 | _arrayPool.Add(length, stack); 31 | } 32 | 33 | if (!stack.TryPop(out var array)) 34 | array = new T[length]; 35 | 36 | _borrowedArrays.Add(array); 37 | return array; 38 | } 39 | 40 | public static void ReclaimAll() 41 | { 42 | foreach (var list in _borrowedLists) 43 | { 44 | list.Clear(); 45 | _listPool.Push(list); 46 | } 47 | 48 | foreach (var array in _borrowedArrays) 49 | { 50 | if (!_arrayPool.TryGetValue(array.Length, out var stack)) 51 | { 52 | stack = new Stack(); 53 | _arrayPool[array.Length] = stack; 54 | } 55 | 56 | Array.Clear(array); 57 | 58 | stack.Push(array); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace PrimerTools 5 | { 6 | public static class StringExtensions 7 | { 8 | public static string Join(this IEnumerable enumerable, string separator) 9 | { 10 | return string.Join(separator, enumerable.Select(x => x.ToString())); 11 | } 12 | 13 | public static string Join(this IEnumerable strings, string separator) 14 | { 15 | return string.Join(separator, strings); 16 | } 17 | 18 | public static string ToValidNodeName(this string str) 19 | { 20 | // These are the characters that Godot replaces with underscores 21 | char[] invalidChars = new[] { '.', ':', '@', '/', '"', '%' }; 22 | 23 | foreach (char invalidChar in invalidChars) 24 | { 25 | str = str.Replace(invalidChar, '_'); 26 | } 27 | 28 | return str; 29 | } 30 | 31 | // Copied from 32 | // https://andrewlock.net/why-is-string-gethashcode-different-each-time-i-run-my-program-in-net-core/ 33 | public static int GetDeterministicHashCode(this string str) 34 | { 35 | unchecked { 36 | var hash1 = (5381 << 16) + 5381; 37 | var hash2 = hash1; 38 | 39 | for (var i = 0; i < str.Length; i += 2) { 40 | hash1 = ((hash1 << 5) + hash1) ^ str[i]; 41 | 42 | if (i == str.Length - 1) 43 | break; 44 | 45 | hash2 = ((hash2 << 5) + hash2) ^ str[i + 1]; 46 | } 47 | 48 | return hash1 + (hash2 * 1566083941); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Simulation/SimSpeedDisplay.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools; 3 | using PrimerTools.LaTeX; 4 | using PrimerTools.Simulation; 5 | 6 | public partial class SimSpeedDisplay : Node3D 7 | { 8 | // TODO: Decide whether to keep this. It's kind of nice, but it would need to go to zero when the sim world is paused. 9 | // For now, I commented out the parts that make it follow the sim world, and instead made the update method public. 10 | // 11 | 12 | // private SimulationWorld _simulationWorld; 13 | public LatexNode _latexNode; 14 | public float MultiplierForLying = 1; 15 | private int _initialValue; 16 | 17 | public SimSpeedDisplay(int initialValue) 18 | { 19 | // _simulationWorld = simulationWorld; 20 | _initialValue = initialValue; 21 | } 22 | 23 | public override void _Ready() 24 | { 25 | base._Ready(); 26 | // SimulationWorld.TimeScaleChanged += UpdateDisplay; 27 | 28 | _latexNode = new LatexNode(); 29 | _latexNode.numberPrefix = "\\times"; 30 | _latexNode.NumericalExpression = _initialValue; 31 | _latexNode.HorizontalAlignment = LatexNode.HorizontalAlignmentOptions.Left; 32 | AddChild(_latexNode); 33 | Name = "Sim speed display"; 34 | // UpdateDisplay(_simulationWorld.TimeScaleControl); 35 | } 36 | 37 | public void UpdateDisplay(float speed, double duration = AnimationUtilities.DefaultDuration) 38 | { 39 | GD.Print("Updating speed display"); 40 | if (!IsInstanceValid(this)) 41 | { 42 | GD.PushWarning("Invalid SimSpeedDisplay"); 43 | return; 44 | } 45 | var tween = CreateTween(); 46 | tween.TweenProperty( 47 | _latexNode, 48 | "NumericalExpression", 49 | speed * MultiplierForLying, 50 | duration 51 | ); 52 | } 53 | 54 | public void SetToDefaultPosition() 55 | { 56 | Position = new Vector3(-19.6f, -10.3f, -43.4f); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Extensions/Vector3Extensions.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools; 4 | 5 | public static class Vector3Extensions 6 | { 7 | public static bool IsLengthGreaterThan(this Vector3 vec, float length) 8 | { 9 | return vec.LengthSquared() > length * length; 10 | } 11 | public static bool IsLengthLessThan(this Vector3 vec, float length) 12 | { 13 | return vec.LengthSquared() < length * length; 14 | } 15 | 16 | /// 17 | /// Finds a point between vec and otherVec, cutLength away from otherVec. Effectively travels from vec to otherVec, 18 | /// but stops short by cutLength. Similar to Lerp, but with an absolute length rather than a fraction. 19 | /// This isn't clamped, so if cutLength is negative or larger than the distance between the two vectors, 20 | /// the returned vector will be outside the region between the vec and otherVec. 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// 26 | public static Vector3 AllTheWayMinusLength(this Vector3 vec, Vector3 otherVec, float cutLength) 27 | { 28 | // If length is greater than the distance between the two vectors. This returns a vector pointing away. 29 | return vec + (otherVec - vec).ShortenLengthBy(cutLength); 30 | 31 | // var fullDisplacement = otherVec - vec; 32 | // var fullLength = fullDisplacement.Length(); 33 | // return vec + fullDisplacement / fullLength * (fullLength - cutLength); 34 | } 35 | 36 | public static Vector3 ShortenLengthBy(this Vector3 vec, float cutLength) 37 | { 38 | var fullLength = vec.Length(); 39 | return vec / fullLength * (fullLength - cutLength); 40 | } 41 | } -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Components/AreaComponent.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation; 4 | 5 | public struct AreaComponent : IPhysicsObjectHandler 6 | { 7 | public Rid Area { get; private set; } 8 | public Shape3D Shape { get; private set; } 9 | public Transform3D LocalTransform3D { get; private set; } 10 | 11 | public void Initialize(Rid space, Transform3D transform, Transform3D localTransform3D, Shape3D shape, uint collisionLayer = 1, uint collisionMask = 1) 12 | { 13 | var area = PhysicsServer3D.AreaCreate(); 14 | PhysicsServer3D.AreaSetSpace(area, space); 15 | LocalTransform3D = localTransform3D; 16 | PhysicsServer3D.AreaSetTransform(area, transform * localTransform3D); 17 | PhysicsServer3D.AreaAddShape(area, shape.GetRid()); 18 | PhysicsServer3D.AreaSetCollisionLayer(area, collisionLayer); 19 | PhysicsServer3D.AreaSetCollisionMask(area, collisionMask); 20 | 21 | Area = area; 22 | Shape = shape; 23 | } 24 | 25 | public void CleanUp() 26 | { 27 | Shape?.Dispose(); 28 | if (Area == default) return; 29 | PhysicsServer3D.FreeRid(Area); 30 | } 31 | 32 | public void UpdateTransform(Transform3D transform) 33 | { 34 | PhysicsServer3D.AreaSetTransform(Area, transform * LocalTransform3D); 35 | } 36 | 37 | public Area3D ConstructDebugNode(Node3D parent) 38 | { 39 | var bodyArea = new Area3D(); 40 | bodyArea.CollisionLayer = 0; 41 | bodyArea.CollisionMask = 0; 42 | parent.AddChild(bodyArea); 43 | var bodyShape = new CollisionShape3D(); 44 | bodyArea.AddChild(bodyShape); 45 | bodyShape.Shape = Shape; 46 | bodyArea.Transform = LocalTransform3D; 47 | return bodyArea; 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /Graph/Axis/AxisTic.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools.LaTeX; 3 | using PrimerTools.TweenSystem; 4 | 5 | namespace PrimerTools.Graph; 6 | 7 | [Tool] 8 | public partial class AxisTic : Node3D 9 | { 10 | public Axis.TicData Data; 11 | 12 | private LatexNode LatexNode => GetNode("LatexNode"); 13 | 14 | public void SetLabel() 15 | { 16 | LatexNode.Latex = Data.label; 17 | LatexNode.UpdateCharacters(); 18 | this.MakeSelfAndChildrenLocal(GetTree().EditedSceneRoot); 19 | } 20 | 21 | public void SetLabelScale(float scale) 22 | { 23 | LatexNode.Scale = Vector3.One * scale; 24 | } 25 | 26 | public Animation AnimateLabelScale(float scale) 27 | { 28 | return LatexNode.ScaleToAnimation(scale); 29 | } 30 | 31 | public IStateChange AnimateLabelScaleStateChange(float scale) 32 | { 33 | return LatexNode.ScaleTo(scale); 34 | } 35 | 36 | public void SetLabelDistance(float? distance) 37 | { 38 | if (distance.HasValue) 39 | { 40 | LatexNode.Position = new Vector3(LatexNode.Position.X, -distance.Value, LatexNode.Position.Z); 41 | } 42 | // If no distance specified, keep the default position from the scene 43 | } 44 | 45 | public Animation AnimateLabelDistance(float? distance) 46 | { 47 | if (!distance.HasValue) 48 | return null; 49 | 50 | return LatexNode.MoveToAnimation( 51 | new Vector3(LatexNode.Position.X, -distance.Value, LatexNode.Position.Z) 52 | ); 53 | } 54 | 55 | public IStateChange AnimateLabelDistanceStateChange(float? distance) 56 | { 57 | if (!distance.HasValue) 58 | return null; 59 | 60 | return LatexNode.MoveTo( 61 | new Vector3(LatexNode.Position.X, -distance.Value, LatexNode.Position.Z) 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/TreeSim/Visual/FruitVisualEventManager.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools.Simulation; 3 | using PrimerTools.Simulation.Components; 4 | using PrimerTools.Simulation.Visual; 5 | 6 | namespace PrimerTools.Simulation.Visual; 7 | 8 | public class FruitVisualEventManager : IVisualEventManager 9 | { 10 | private readonly VisualEntityRegistry _visualRegistry; 11 | 12 | public FruitVisualEventManager(VisualEntityRegistry visualRegistry) 13 | { 14 | _visualRegistry = visualRegistry; 15 | _visualRegistry.RegisterEntityType(); 16 | _visualRegistry.SubscribeToComponentEvents(); 17 | 18 | // Subscribe to fruit events 19 | // FruitSystem.FruitRipenedEvent += OnFruitRipened; 20 | // FruitSystem.FruitDetachedEvent += OnFruitDetached; 21 | FruitSystem.FruitDecayedEvent += OnFruitDecayed; 22 | } 23 | 24 | // private void OnFruitRipened(EntityId entityId) 25 | // { 26 | // if (_visualRegistry.TryGetVisualEntity(entityId, out var fruitVisual)) 27 | // { 28 | // fruitVisual.HandleRipened(); 29 | // } 30 | // } 31 | // 32 | // private void OnFruitDetached(EntityId entityId) 33 | // { 34 | // if (_visualRegistry.TryGetVisualEntity(entityId, out var fruitVisual)) 35 | // { 36 | // fruitVisual.HandleDetached(); 37 | // } 38 | // } 39 | // 40 | private void OnFruitDecayed(EntityId entityId) 41 | { 42 | _visualRegistry.GetVisualEntity(entityId).HandleDecayed(); 43 | } 44 | 45 | public void Cleanup() 46 | { 47 | // FruitSystem.FruitRipenedEvent -= OnFruitRipened; 48 | // FruitSystem.FruitDetachedEvent -= OnFruitDetached; 49 | FruitSystem.FruitDecayedEvent -= OnFruitDecayed; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Visual/VisualEntity.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation; 4 | 5 | public abstract partial class VisualEntity : Node3D, IVisualEntity 6 | { 7 | public EntityId EntityId { get; private set; } 8 | public Node3D RootNode => this; 9 | 10 | // TODO: Consider eliminating this 11 | // Really, this method's purpose is to tell the visual entity 12 | // which data entity it represents. 13 | // This could be handled in the constructor. 14 | // But it's a lil weird because the factories methods would be affected. 15 | // It's fine for now. 16 | public virtual void Initialize(EntityRegistry registry, EntityId entityId) 17 | { 18 | EntityId = entityId; 19 | } 20 | 21 | public abstract void Update(EntityRegistry registry); 22 | public void AddDebugNodes(params IPhysicsObjectHandler[] bodyComponents) 23 | { 24 | foreach (var phys in bodyComponents) 25 | { 26 | phys.ConstructDebugNode(this); 27 | } 28 | } 29 | 30 | // This is for a theoretical future where there are multiple visual components together 31 | // For example, a creature with an emotion or intention indicator. The indicator might have its own data component. 32 | // But the visual indicators should be attached to the creature node rather than being an independent visual entity. 33 | // Leaving this commented rather than deleting to record the idea that visual components 34 | // can be composed into visual entities. 35 | // protected readonly List VisualComponents = new(); 36 | // protected void AddVisualComponent(IVisualComponent component) 37 | // { 38 | // component.Initialize(this); 39 | // VisualComponents.Add(component); 40 | // } 41 | // public interface IVisualComponent 42 | // { 43 | // void Initialize(Node3D parent); 44 | // void Update(EntityRegistry registry); 45 | // } 46 | } 47 | -------------------------------------------------------------------------------- /2D/ImageDisplayMesh.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools; 3 | 4 | [Tool] 5 | public partial class ImageDisplayMesh : MeshInstance3D 6 | { 7 | private Texture2D imageTexture; 8 | private Vector2 size; 9 | public Vector2 Size => size; 10 | [Export] public Texture2D ImageTexture 11 | { 12 | get => imageTexture; 13 | set 14 | { 15 | if (value == null) return; 16 | imageTexture = value; 17 | size = new Vector2(value.GetWidth(), value.GetHeight()); 18 | Update(); 19 | } 20 | } 21 | 22 | public static ImageDisplayMesh Create(string path) 23 | { 24 | var idm = new ImageDisplayMesh(); 25 | idm.ImageTexture = ResourceLoader.Load(path); 26 | return idm; 27 | } 28 | 29 | private void Update() 30 | { 31 | if (ImageTexture == null) 32 | { 33 | GD.PrintErr("ImageTexture is not assigned."); 34 | return; 35 | } 36 | 37 | // Create a plane mesh with the same aspect ratio as the image 38 | var planeMesh = new PlaneMesh(); 39 | planeMesh.Size = size; 40 | 41 | // Assign the mesh to the MeshInstance3D 42 | Mesh = planeMesh; 43 | 44 | // Create a new material and set the image texture 45 | var material = new StandardMaterial3D(); 46 | material.AlbedoTexture = ImageTexture; 47 | // material.CullMode = BaseMaterial3D.CullModeEnum.Disabled; 48 | 49 | // Assign the material to the mesh surface 50 | SetSurfaceOverrideMaterial(0, material); 51 | } 52 | 53 | public void AllowTransparency() 54 | { 55 | var mat = this.GetOrCreateOverrideMaterial(); 56 | mat.Transparency = BaseMaterial3D.TransparencyEnum.Alpha; 57 | } 58 | 59 | public void MakeUnshaded() 60 | { 61 | var mat = this.GetOrCreateOverrideMaterial(); 62 | mat.ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded; 63 | } 64 | } -------------------------------------------------------------------------------- /2D/CanvasImitator/CanvasImitator.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools; 3 | 4 | public partial class CanvasImitator : Node3D 5 | { 6 | // The purpose of this class is to make a 2D space that appears in the camera preview. 7 | // This is useful for composing scenes that involve both 2D and 3D objects. 8 | 9 | protected int SubViewPortWidth = 1920; 10 | protected int SubViewPortHeight = 1080; 11 | 12 | protected float CamFov => GetParent().Fov; 13 | protected float CamNearPlane => GetParent().Near; 14 | protected float DoubleCamNearPlane => 2 * GetParent().Near; 15 | protected MeshInstance3D DisplayMeshInstance; 16 | protected SubViewport SubViewPort; 17 | 18 | public void CreateDisplayMesh() 19 | { 20 | var subViewPortContainer = new SubViewportContainer(); 21 | AddChild(subViewPortContainer); 22 | subViewPortContainer.Owner = GetTree().EditedSceneRoot; 23 | 24 | SubViewPort = new SubViewport(); 25 | subViewPortContainer.AddChild(SubViewPort); 26 | SubViewPort.Owner = GetTree().EditedSceneRoot; 27 | SubViewPort.Size = new Vector2I(SubViewPortWidth, SubViewPortHeight); 28 | SubViewPort.TransparentBg = true; 29 | 30 | DisplayMeshInstance = new MeshInstance3D(); 31 | var viewPortRendererMesh = new PlaneMesh(); 32 | viewPortRendererMesh.Size = new Vector2(16f/9, 1); 33 | DisplayMeshInstance.Mesh = viewPortRendererMesh; 34 | AddChild(DisplayMeshInstance); 35 | DisplayMeshInstance.Owner = GetTree().EditedSceneRoot; 36 | 37 | var mat = new StandardMaterial3D(); 38 | mat.Transparency = BaseMaterial3D.TransparencyEnum.Alpha; 39 | mat.AlbedoTexture = SubViewPort.GetTexture(); 40 | DisplayMeshInstance.Mesh.SurfaceSetMaterial(0, mat); 41 | 42 | // Transformation 43 | DisplayMeshInstance.RotationDegrees = new Vector3(90, 0, 0); 44 | DisplayMeshInstance.Position = new Vector3(0, 0, -DoubleCamNearPlane); 45 | var scale = 2 * DoubleCamNearPlane * Mathf.Tan(CamFov / 2 * Mathf.Pi / 180); 46 | DisplayMeshInstance.Scale = Vector3.One * scale; 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Graph/Resources/Axis.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &8141656979337668102 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 8141656979337668103} 12 | - component: {fileID: 4748708022717725990} 13 | m_Layer: 0 14 | m_Name: Axis 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &8141656979337668103 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 8141656979337668102} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_ConstrainProportionsScale: 0 31 | m_Children: [] 32 | m_Father: {fileID: 0} 33 | m_RootOrder: 0 34 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 35 | --- !u!114 &4748708022717725990 36 | MonoBehaviour: 37 | m_ObjectHideFlags: 0 38 | m_CorrespondingSourceObject: {fileID: 0} 39 | m_PrefabInstance: {fileID: 0} 40 | m_PrefabAsset: {fileID: 0} 41 | m_GameObject: {fileID: 8141656979337668102} 42 | m_Enabled: 1 43 | m_EditorHideFlags: 0 44 | m_Script: {fileID: 11500000, guid: d251cc4992cf4d9ab447b71da57a6abc, type: 3} 45 | m_Name: 46 | m_EditorClassIdentifier: 47 | arrowPresence: 2 48 | arrowPrefab: {fileID: 2477842104010458270, guid: c9246c75b0bea4296b6d948b371ca68f, type: 3} 49 | _range: 50 | min: 0 51 | max: 10 52 | padding: {x: 0, y: 0} 53 | _length: 1 54 | showLabel: 1 55 | label: Label 56 | labelOffset: {x: 0, y: 0, z: 0} 57 | labelRotation: {x: 0, y: 0, z: 0, w: 1} 58 | labelPosition: 1 59 | thickness: 1 60 | showTicks: 1 61 | showZero: 0 62 | lockTickOrientation: 63 | _enabled: 1 64 | _value: 4 65 | step: 2 66 | maxTicks: 50 67 | maxDecimals: 2 68 | tickOffset: 0 69 | labelNumberOffset: 0 70 | valuePositionOffset: 0 71 | manualTicks: [] 72 | tickPrefab: {fileID: 0} 73 | -------------------------------------------------------------------------------- /Environment/primer_environment.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=4 format=3 uid="uid://xpav3hoy6ldu"] 2 | 3 | [ext_resource type="Shader" uid="uid://ddq02620nwc1d" path="res://addons/PrimerTools/Environment/sky_shader2.gdshader" id="1_1cjjy"] 4 | 5 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_yvsqb"] 6 | shader = ExtResource("1_1cjjy") 7 | shader_parameter/time_offset = 0.0 8 | shader_parameter/base_color = Color(0.0511276, 0.0573691, 0.062142, 1) 9 | shader_parameter/mist_color = Color(0.184, 0.2, 0.212, 1) 10 | shader_parameter/lighting_color = Color(0.5, 0.5, 0.5, 1) 11 | shader_parameter/mist_scale = 64.185 12 | shader_parameter/mist_speed = 0.15 13 | shader_parameter/mist_intensity = 0.5 14 | shader_parameter/perlin_layers = 0 15 | shader_parameter/worley_layers = 0 16 | shader_parameter/voronoi_edge_layers = 3 17 | shader_parameter/grid_layers = 0 18 | shader_parameter/crystalline_layers = 0 19 | shader_parameter/hexagonal_layers = 5 20 | shader_parameter/line_network_layers = 0 21 | shader_parameter/mondrian_layers = 0 22 | shader_parameter/circuit_layers = 0 23 | shader_parameter/grid_size = 0.5 24 | shader_parameter/line_thickness = 0.1 25 | shader_parameter/curl_influence = 1.0 26 | shader_parameter/layer1_octaves = 3 27 | shader_parameter/layer2_octaves = 3 28 | shader_parameter/layer3_octaves = 3 29 | shader_parameter/distortion_scale = 1.5 30 | shader_parameter/distortion_speed = 0.2 31 | shader_parameter/domain_warp_strength = 0.0 32 | shader_parameter/quantization_levels = 0 33 | shader_parameter/edge_detection_strength_layer1 = 0.0 34 | shader_parameter/edge_detection_strength_layer2 = 0.0 35 | shader_parameter/edge_detection_strength_layer3 = 0.0 36 | shader_parameter/contrast_boost = 1.0 37 | shader_parameter/use_rotation = 0 38 | shader_parameter/rotation_speed = 0.0 39 | shader_parameter/use_spherical_mapping = 0 40 | shader_parameter/show_noise_only = 0 41 | 42 | [sub_resource type="Sky" id="Sky_twrfi"] 43 | sky_material = SubResource("ShaderMaterial_yvsqb") 44 | 45 | [resource] 46 | background_mode = 2 47 | background_color = Color(0.184314, 0.2, 0.211765, 0) 48 | sky = SubResource("Sky_twrfi") 49 | ambient_light_color = Color(1, 1, 1, 1) 50 | sdfgi_enabled = true 51 | fog_mode = 1 52 | fog_density = 1.0 53 | -------------------------------------------------------------------------------- /Graph/DataObjects/PointData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | 4 | namespace PrimerTools.Graph; 5 | 6 | public partial class PointData : Node3D, IPrimerGraphData 7 | { 8 | private Graph Graph => GetParent(); 9 | private List<(Vector3 position, MeshInstance3D node)> pointObjects = new(); 10 | 11 | public void AddPoints(params Vector3[] positions) 12 | { 13 | foreach (var pos in positions) 14 | { 15 | var point = new MeshInstance3D(); 16 | point.Mesh = new SphereMesh(); 17 | point.Scale = Vector3.One * 0.2f; 18 | point.Name = "Point"; 19 | AddChild(point); 20 | point.Owner = GetTree().EditedSceneRoot; 21 | point.Position = Graph.GetDataSpaceToPositionSpaceFromSettings(pos); 22 | pointObjects.Add((pos, point)); 23 | } 24 | } 25 | 26 | public void SetData(params Vector3[] data) 27 | { 28 | // TODO: Make this handle situations where the data is longer or shorter than the current data. 29 | // Might be better to have the data and object lists be separate and handle adding/removing point objects 30 | // during animations. 31 | for (var i = 0; i < data.Length; i++) 32 | { 33 | pointObjects[i] = (data[i], pointObjects[i].node); 34 | } 35 | } 36 | 37 | public void FetchData() 38 | { 39 | throw new System.NotImplementedException(); 40 | } 41 | 42 | public Animation Transition(double duration) 43 | { 44 | var transitionAnimations = new List(); 45 | foreach (var (position, node) in pointObjects) 46 | { 47 | transitionAnimations.Add(node.MoveToAnimation(Graph.GetDataSpaceToPositionSpaceFromSettings(position))); 48 | } 49 | 50 | return transitionAnimations.InParallel(); 51 | } 52 | 53 | public IStateChange TransitionStateChange(double duration) 54 | { 55 | throw new System.NotImplementedException(); 56 | } 57 | 58 | public Tween TweenTransition(double duration) 59 | { 60 | throw new System.NotImplementedException(); 61 | } 62 | 63 | public IStateChange Disappear() 64 | { 65 | throw new System.NotImplementedException(); 66 | } 67 | } -------------------------------------------------------------------------------- /Utilities/TempDir.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | 5 | namespace PrimerTools 6 | { 7 | public class TempDir : IDisposable 8 | { 9 | private readonly DirectoryInfo info; 10 | private int childrenCount = 0; 11 | private readonly bool isRoot; 12 | private bool exists = false; 13 | 14 | public string FullPath => info.FullName; 15 | 16 | public TempDir() 17 | { 18 | var tempPath = Path.GetTempPath(); 19 | var tmpDir = Path.Combine(tempPath, $"godot-primer-{Guid.NewGuid()}"); 20 | info = Directory.CreateDirectory(tmpDir); 21 | isRoot = true; 22 | exists = true; 23 | } 24 | 25 | private TempDir(DirectoryInfo info) 26 | { 27 | this.info = info; 28 | isRoot = false; 29 | exists = true; 30 | } 31 | 32 | ~TempDir() => CleanUpResources(); 33 | 34 | public void Dispose() => CleanUpResources(); 35 | 36 | public void Open() 37 | { 38 | Process.Start($"{FullPath}{Path.DirectorySeparatorChar}"); 39 | } 40 | 41 | public string GetChildPath(string filename) 42 | { 43 | return Path.Combine(info.FullName, filename); 44 | } 45 | 46 | public TempDir CreateChild(string name, bool autoIncrement = false) 47 | { 48 | if (autoIncrement) 49 | name += childrenCount++; 50 | else if (string.IsNullOrWhiteSpace(name)) 51 | name = $"{childrenCount++}"; 52 | 53 | var child = info.CreateSubdirectory(name); 54 | return new TempDir(child); 55 | } 56 | 57 | public override string ToString() => info.FullName; 58 | 59 | private void CleanUpResources() 60 | { 61 | if (!exists || !isRoot) 62 | return; 63 | 64 | void DeleteRecursively(DirectoryInfo directory) 65 | { 66 | foreach (var subDirectory in directory.EnumerateDirectories()) 67 | DeleteRecursively(subDirectory); 68 | 69 | directory.Delete(true); 70 | } 71 | 72 | DeleteRecursively(info); 73 | exists = false; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/TreeSim/FruitTreeSimSettings.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation; 4 | public class FruitTreeSimSettings 5 | { 6 | #region Distribution Save/Load 7 | public static string TreeDistributionPath { get; set; } 8 | public bool LoadTreeDistribution => !string.IsNullOrEmpty(TreeDistributionPath); 9 | #endregion 10 | 11 | #region Tree settings 12 | public static float MaxTreeSpawnRadius = 8f; 13 | public static float MinTreeSpawnRadius = 2f; 14 | public static float TreeCompetitionRadius = 6f; 15 | public static float MinimumTreeDistance = 2f; 16 | 17 | public const float TreeMaturationTime = 10f; 18 | public const float TreeSpawnInterval = 5f; 19 | 20 | public const float DeathCheckInterval = 0.2f; 21 | public const float SaplingDeathProbabilityBase = 0.0001f; 22 | public const float SaplingDeathProbabilityPerNeighbor = 0.01f; 23 | public const float MatureTreeDeathProbabilityBase = 0.0001f; 24 | public const float MatureTreeDeathProbabilityPerNeighbor = 0.0002f; 25 | #endregion 26 | 27 | #region Fruit Settings 28 | // Growth and lifecycle 29 | public static float FruitRipeningTime = 5.0f; // Time to ripen after fully grown 30 | public static float FruitDecayTime = 10.0f; // Time until fruit decays after falling 31 | 32 | public static float FruitGrowthTime = 4f; 33 | public static float NodeFruitGrowthDelay = 2f; // This is only visual. Kinda doesn't belong here. 34 | 35 | // Physics properties 36 | public static float FruitMass = 0.5f; // Mass of fruit for physics 37 | public static float FruitRadius = 0.925f; // Radius of fruit collision sphere 38 | 39 | // Probabilities 40 | public static float RipeFruitFallProbabilityPerSecond = 0.05f; // Chance per second for ripe fruit to fall 41 | 42 | // Standard fruit positions on tree (relative to tree origin) 43 | public static readonly Vector3[] StandardFruitPositions = new Vector3[] 44 | { 45 | new Vector3(0.8f, 1.5f, 0.6f), 46 | new Vector3(-0.7f, 1.7f, 0.5f), 47 | new Vector3(0.5f, 1.9f, -0.6f), 48 | new Vector3(-0.6f, 1.6f, -0.7f) 49 | }; 50 | 51 | // Maximum number of fruits per tree 52 | public static int MaxFruitsPerTree = 1; 53 | #endregion 54 | } 55 | -------------------------------------------------------------------------------- /2D/Diagram/ShapeShaders/arrow_shader_solo.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | render_mode cull_disabled; 3 | 4 | #include "sdf_primitives.gdshaderinc" 5 | #include "sdf_common.gdshaderinc" 6 | 7 | uniform vec4 shape_color : source_color = vec4(1.0, 0.5, 0.0, 1.0); 8 | uniform vec4 background_color : source_color = vec4(0.0, 0.0, 0.0, 0.0); 9 | uniform float thickness : hint_range(0, 2) = 0.1; 10 | uniform float smoothness : hint_range(0, 2) = 0.01; 11 | 12 | // Arrow-specific parameters 13 | uniform vec2 arrow_start = vec2(-1.0, 0.0); 14 | uniform vec2 arrow_end = vec2(1.0, 0.0); 15 | uniform float head_length = 0.3; 16 | uniform float head_angle = 30.0; // degrees 17 | 18 | varying vec2 object_pos; 19 | 20 | void vertex() { 21 | // Pass object-space position to fragment shader 22 | object_pos = vec2(VERTEX.x, -VERTEX.z); 23 | } 24 | 25 | //void fragment() { 26 | //// Use object-space coordinates 27 | //vec2 p = object_pos; 28 | // 29 | //float d = sdArrow(p, arrow_start, arrow_end, head_length, head_angle); 30 | //d = d - thickness; 31 | // 32 | //// Apply smoothstep for antialiasing 33 | //float alpha = 1.0 - smoothstep(0.0, smoothness, d); 34 | // 35 | //// Mix colors based on the SDF 36 | //vec3 color = mix(background_color.rgb, shape_color.rgb, alpha); 37 | //float final_alpha = mix(background_color.a, shape_color.a, alpha); 38 | // 39 | //ALBEDO = color; 40 | //ALPHA = final_alpha; 41 | //} 42 | 43 | void fragment() { 44 | vec2 p = object_pos; 45 | 46 | // Evaluate curly bracket with variable thickness 47 | float d = sdArrow(p, arrow_start, arrow_end, head_length, head_angle); 48 | d = d - thickness; 49 | 50 | // Calculate screen-space derivatives of the distance field itself 51 | float d_dx = dFdx(d); 52 | float d_dy = dFdy(d); 53 | float grad_len = length(vec2(d_dx, d_dy)); 54 | 55 | // Normalize the gradient to get consistent AA width 56 | float aa_width = smoothness * max(grad_len, 0.0001); 57 | 58 | // Apply smoothstep with gradient-based anti-aliasing 59 | float alpha = 1.0 - smoothstep(0.0, aa_width, d); 60 | 61 | // Mix colors based on the SDF 62 | vec3 color = mix(background_color.rgb, shape_color.rgb, alpha); 63 | float final_alpha = mix(background_color.a, shape_color.a, alpha); 64 | 65 | ALBEDO = color; 66 | ALPHA = final_alpha; 67 | } -------------------------------------------------------------------------------- /Graph/Testing/BarPlot3DTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | using PrimerTools.Graph; 4 | 5 | [Tool] 6 | public partial class BarPlot3DTest : Node3D 7 | { 8 | private bool _run; 9 | [Export] 10 | public bool Run 11 | { 12 | get => _run; 13 | set 14 | { 15 | _run = value; 16 | if (value) 17 | { 18 | // Clear any existing children 19 | foreach (var child in GetChildren()) 20 | { 21 | child.Free(); 22 | } 23 | 24 | CreateGraph(); 25 | } 26 | } 27 | } 28 | 29 | private async void CreateGraph() 30 | { 31 | // Create the graph 32 | var graph = Graph.CreateInstance(); 33 | AddChild(graph); 34 | 35 | // Configure the axes 36 | graph.XAxis.length = 10; 37 | graph.YAxis.length = 10; 38 | graph.ZAxis.length = 10; 39 | 40 | graph.XAxis.Max = 3; 41 | graph.YAxis.Max = 5; 42 | graph.ZAxis.Max = 3; 43 | 44 | graph.XAxis.TicStep = 1; 45 | graph.YAxis.TicStep = 1; 46 | graph.ZAxis.TicStep = 1; 47 | graph.Transition(); 48 | 49 | // Create the bar plot 50 | graph.Owner = GetTree().EditedSceneRoot; 51 | var barPlot = graph.AddBarPlot3D(); 52 | // var barPlot = new BarPlot3D(3, 3); // 3x3 grid 53 | // graph.AddChild(barPlot); 54 | 55 | // Create sample data (9 values for 3x3 grid) 56 | var data = new float[,] 57 | { 58 | { 1.0f, 2.0f, 3.0f }, 59 | { 2.0f, 4.0f, 2.0f }, 60 | { 3.0f, 1.0f, 2.0f } 61 | }; 62 | var data2 = new float[,] 63 | { 64 | { 2.0f, 1.0f, 4.0f }, 65 | { 1.0f, 5.0f, 1.0f }, 66 | { 4.0f, 0.0f, 3.0f } 67 | }; 68 | var datas = new List(); 69 | datas.Add(data); 70 | datas.Add(data2); 71 | 72 | var index = 0; 73 | while (_run) 74 | { 75 | barPlot.DataFetchMethod = () => datas[index++ % datas.Count]; 76 | barPlot.FetchData(); 77 | var tween = barPlot.TweenTransition(); 78 | await tween.ToSignal(tween, Tween.SignalName.Finished); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Utilities/MeshUtilities.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | 4 | namespace PrimerTools.Utilities; 5 | 6 | public static class MeshUtilities 7 | { 8 | // This is for triangle-type meshes in index mode 9 | public static void AddTriangle(this List indices, int a, int b, int c, bool flip = false) 10 | { 11 | if (flip) 12 | { 13 | indices.Add(a); 14 | indices.Add(c); 15 | indices.Add(b); 16 | return; 17 | } 18 | indices.Add(a); 19 | indices.Add(b); 20 | indices.Add(c); 21 | } 22 | public static void MakeDoubleSided(ref Vector3[] vertices, ref int[] indices, ref Vector3[] normals) 23 | { 24 | GD.PushWarning("You're making the mesh double sided. It might be better to disable culling on the material or shader."); 25 | 26 | // Prepare arrays to contain vertices and triangles for both sides 27 | // If doubleSided is false, the empty entries won't matter 28 | var verticesDouble = new Vector3[vertices.Length * 2]; 29 | var trianglesDouble = new int[indices.Length * 2]; 30 | var normalsDouble = new Vector3[normals.Length * 2]; 31 | 32 | // Fill the vertices and triangles for the first side 33 | vertices.CopyTo(verticesDouble, 0); 34 | indices.CopyTo(trianglesDouble, 0); 35 | normals.CopyTo(normalsDouble, 0); 36 | 37 | // Add the copied set of vertices 38 | vertices.CopyTo(verticesDouble, vertices.Length); 39 | // Add the copied set of triangles, but reverse the order of the vertices for each one 40 | // so that the normals point in the opposite direction. 41 | for (var i = 0; i < indices.Length; i += 3) 42 | { 43 | trianglesDouble[i + indices.Length] = indices[i + 2] + vertices.Length; 44 | trianglesDouble[i + 1 + indices.Length] = indices[i + 1] + vertices.Length; 45 | trianglesDouble[i + 2 + indices.Length] = indices[i] + vertices.Length; 46 | } 47 | // Flip the second half of the normals 48 | for (var i = 0; i < normals.Length; i++) 49 | { 50 | normalsDouble[i + normals.Length] = -normals[i]; 51 | } 52 | 53 | vertices = verticesDouble; 54 | indices = trianglesDouble; 55 | normals = normalsDouble; 56 | } 57 | } -------------------------------------------------------------------------------- /StateChangeAnimationSystem/StateChangeSequence.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | public abstract partial class StateChangeSequence : Node3D 4 | { 5 | [Export] public bool Active = true; 6 | public readonly CompositeStateChange RootComposite = new(); 7 | public abstract void Define(); 8 | 9 | protected void AddStateChange(IStateChange stateChange, double absoluteTime = -1, bool log = false) 10 | { 11 | RootComposite.AddStateChange(stateChange, absoluteTime, log); 12 | } 13 | 14 | protected void AddStateChange(IStateChange stateChange, int minutes, float seconds) 15 | { 16 | RootComposite.AddStateChange(stateChange, minutes, seconds); 17 | } 18 | 19 | protected void AddStateChange(IStateChange stateChange, int minutes, int seconds, int frames) 20 | { 21 | RootComposite.AddStateChange(stateChange, minutes, seconds, frames); 22 | } 23 | 24 | protected void AddStateChangeWithDelay(IStateChange stateChange, double delay = 0) 25 | { 26 | RootComposite.AddStateChangeWithDelay(stateChange, delay); 27 | } 28 | 29 | // Removing the ones with minute-scale delays. 30 | // They are never used and make it more likely to accidentally add a delay instead of an absolute time. 31 | // protected void AddStateChangeWithDelay(IStateChange stateChange, int delayMinutes, float delaySeconds) 32 | // { 33 | // RootComposite.AddStateChangeWithDelay(stateChange, delayMinutes, delaySeconds); 34 | // } 35 | // 36 | // protected void AddStateChangeWithDelay(IStateChange stateChange, int delayMinutes, int delaySeconds, int delayFrames) 37 | // { 38 | // RootComposite.AddStateChangeWithDelay(stateChange, delayMinutes, delaySeconds, delayFrames); 39 | // } 40 | 41 | protected void AddStateChangeInParallel(IStateChange stateChange, double delay = 0) 42 | { 43 | RootComposite.AddStateChangeInParallel(stateChange, delay); 44 | } 45 | 46 | // protected void AddStateChangeInParallel(IStateChange stateChange, int delayMinutes, float delaySeconds) 47 | // { 48 | // RootComposite.AddStateChangeInParallel(stateChange, delayMinutes, delaySeconds); 49 | // } 50 | // 51 | // protected void AddStateChangeInParallel(IStateChange stateChange, int delayMinutes, int delaySeconds, int delayFrames) 52 | // { 53 | // RootComposite.AddStateChangeInParallel(stateChange, delayMinutes, delaySeconds, delayFrames); 54 | // } 55 | } 56 | -------------------------------------------------------------------------------- /Extensions/Node3DExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | 4 | public static class Node3DExtensions 5 | { 6 | public static Aabb GetBoundingBoxWithChildren(this Node3D node, bool includeChildren = true) 7 | { 8 | var aabb = new Aabb(); 9 | bool first = true; 10 | 11 | var visualNodes = includeChildren ? node.GetAllVisualNodes() : new List(); 12 | 13 | // Add the node itself if it's visual 14 | if (node is VisualInstance3D) 15 | visualNodes.Insert(0, node); 16 | 17 | foreach (var visualNode in visualNodes) 18 | { 19 | if (visualNode is VisualInstance3D visualInstance) 20 | { 21 | var nodeAabb = visualInstance.GetAabb(); 22 | 23 | // The commented-out code avoids an error, but it also stops the thing from working, so 24 | // var relativeTransform = new Transform3D(); 25 | // // Transform to the original node's local space 26 | // if (node.IsInsideTree()) 27 | // { 28 | // relativeTransform = node.GlobalTransform.AffineInverse() * visualNode.GlobalTransform; 29 | // } 30 | var relativeTransform = node.GlobalTransform.AffineInverse() * visualNode.GlobalTransform; 31 | 32 | nodeAabb = relativeTransform * nodeAabb; 33 | 34 | if (first) 35 | { 36 | aabb = nodeAabb; 37 | first = false; 38 | } 39 | else 40 | { 41 | aabb = aabb.Merge(nodeAabb); 42 | } 43 | } 44 | } 45 | 46 | // If no visual nodes found, return a zero-sized AABB at origin 47 | if (first) 48 | { 49 | aabb = new Aabb(Vector3.Zero, Vector3.Zero); 50 | } 51 | 52 | return aabb; 53 | } 54 | 55 | private static List GetAllVisualNodes(this Node3D node) 56 | { 57 | var visualNodes = new List(); 58 | 59 | foreach (var child in node.GetChildren()) 60 | { 61 | if (child is Node3D child3D) 62 | { 63 | if (child3D is VisualInstance3D) 64 | visualNodes.Add(child3D); 65 | 66 | visualNodes.AddRange(child3D.GetAllVisualNodes()); 67 | } 68 | } 69 | 70 | return visualNodes; 71 | } 72 | } -------------------------------------------------------------------------------- /Graph/FromUnity/TernaryPlot/TernaryVectorFieldPlotter.cs: -------------------------------------------------------------------------------- 1 | // using Primer.Graph; 2 | // using Primer.Shapes; 3 | // using Sirenix.OdinInspector; 4 | // using UnityEngine; 5 | // 6 | // [RequireComponent(typeof(TernaryPlot))] 7 | // public abstract class TernaryVectorFieldPlotter : MonoBehaviour 8 | // { 9 | // public bool liveUpdate = false; 10 | // public int automaticPointIncrements = 3; 11 | // public float baseArrowLength = 1; 12 | // public float baseArrowThickness = 1; 13 | // 14 | // protected TernaryPlot ternaryPlot => GetComponent(); 15 | // 16 | // public void OnValidate() 17 | // { 18 | // if (liveUpdate) 19 | // PlotArrows(); 20 | // } 21 | // 22 | // public void TriggeredPlotArrows() 23 | // { 24 | // if (liveUpdate) 25 | // { 26 | // PlotArrows(); 27 | // } 28 | // } 29 | // 30 | // [Button] 31 | // private void PlotArrows() 32 | // { 33 | // SetUp(); 34 | // var gnome = ternaryPlot.GetContentGnome("VectorFieldArrows"); 35 | // 36 | // var points = ternaryPlot.isQuaternary 37 | // ? TernaryPlotUtility.EvenlyDistributedPoints3D(automaticPointIncrements) 38 | // : TernaryPlotUtility.EvenlyDistributedPoints(automaticPointIncrements); 39 | // 40 | // foreach (var point in points) 41 | // { 42 | // var difference = TernaryDifferential(point); 43 | // 44 | // // Get the difference between start and end result as a normalized vector 45 | // var pointAsVector = TernaryPlot.CoordinatesToPosition(point); 46 | // var differenceVector = TernaryPlot.CoordinatesToPosition(difference); 47 | // 48 | // if (!(differenceVector.sqrMagnitude > 0.000001f)) 49 | // continue; 50 | // 51 | // differenceVector /= differenceVector.magnitude; 52 | // var adjustedDifferenceVector = baseArrowLength * differenceVector / automaticPointIncrements; 53 | // 54 | // // Draw the arrow 55 | // var arrow = gnome.AddArrow(); 56 | // arrow.thickness = baseArrowThickness / automaticPointIncrements; 57 | // arrow.tail = pointAsVector - adjustedDifferenceVector / 2; 58 | // arrow.head = pointAsVector + adjustedDifferenceVector / 2; 59 | // } 60 | // 61 | // gnome.Purge(defer: true); 62 | // } 63 | // 64 | // protected abstract void SetUp(); 65 | // 66 | // protected abstract float[] TernaryDifferential(float[] point); 67 | // } 68 | -------------------------------------------------------------------------------- /2D/Diagram/ShapeShaders/curly_bracket_shader.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | render_mode cull_disabled; 3 | 4 | #include "sdf_primitives.gdshaderinc" 5 | #include "sdf_common.gdshaderinc" 6 | 7 | uniform vec4 shape_color : source_color = vec4(1.0, 0.5, 0.0, 1.0); 8 | uniform vec4 background_color : source_color = vec4(0.0, 0.0, 0.0, 0.0); 9 | uniform float thickness : hint_range(0, 0.5) = 0.02; 10 | uniform float thickness_variation : hint_range(0.0, 5.0) = 2.0; 11 | uniform float smoothness : hint_range(0, 10) = 0.01; 12 | 13 | // Bracket parameters 14 | uniform vec2 bracket_tip1 = vec2(-0.5, -1.0); 15 | uniform vec2 bracket_tip2 = vec2(0.5, -1.0); 16 | uniform vec2 bracket_stem = vec2(0.0, 0.0); 17 | uniform vec2 mesh_size = vec2(2.0, 2.0); 18 | 19 | varying vec2 object_pos; 20 | 21 | void vertex() { 22 | object_pos = vec2(VERTEX.x, -VERTEX.z); 23 | } 24 | 25 | //void fragment() { 26 | ////if (object_pos.x > 1.0 && object_pos.y > 1.0) ALBEDO = vec3(0.0); 27 | ////else ALBEDO = vec3(object_pos, 1.0); 28 | //vec2 p = object_pos; 29 | // 30 | //// Evaluate curly bracket with variable thickness 31 | //float d = sdCurlyBracketVariable(p, bracket_tip1, bracket_tip2, bracket_stem, thickness, thickness_variation); 32 | // 33 | //// Apply smoothstep for antialiasing 34 | //float alpha = 1.0 - smoothstep(0.0, smoothness, d); 35 | // 36 | //// Mix colors based on the SDF 37 | //vec3 color = mix(background_color.rgb, shape_color.rgb, alpha); 38 | //float final_alpha = mix(background_color.a, shape_color.a, alpha); 39 | // 40 | //ALBEDO = color; 41 | //ALPHA = final_alpha; 42 | //} 43 | 44 | void fragment() { 45 | vec2 p = object_pos; 46 | 47 | // Evaluate curly bracket with variable thickness 48 | float d = sdCurlyBracketVariable( 49 | p, bracket_tip1, bracket_tip2, bracket_stem, thickness, thickness_variation); 50 | 51 | // Calculate screen-space derivatives of the distance field itself 52 | float d_dx = dFdx(d); 53 | float d_dy = dFdy(d); 54 | float grad_len = length(vec2(d_dx, d_dy)); 55 | 56 | // Normalize the gradient to get consistent AA width 57 | float aa_width = smoothness * max(grad_len, 0.0001); 58 | 59 | // Apply smoothstep with gradient-based anti-aliasing 60 | float alpha = 1.0 - smoothstep(0.0, aa_width, d); 61 | 62 | // Mix colors based on the SDF 63 | vec3 color = mix(background_color.rgb, shape_color.rgb, alpha); 64 | float final_alpha = mix(background_color.a, shape_color.a, alpha); 65 | 66 | ALBEDO = color; 67 | ALPHA = final_alpha; 68 | } 69 | -------------------------------------------------------------------------------- /2D/Diagram/ShapeStyle.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | namespace PrimerTools._2D.Diagram; 5 | 6 | public partial class ShapeStyle : GodotObject 7 | { 8 | private float _thickness = 0.1f; 9 | private float _innerThickness = 0.01f; 10 | private Color _shapeColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); 11 | private Color _backgroundColor = new Color(0.0f, 0.0f, 0.0f, 0.0f); 12 | private float _smoothness = 2.5f; 13 | 14 | public float Thickness 15 | { 16 | get => _thickness; 17 | set 18 | { 19 | _thickness = value; 20 | StyleChanged?.Invoke(); 21 | } 22 | } 23 | 24 | public float InnerThickness 25 | { 26 | get => _innerThickness; 27 | set 28 | { 29 | _innerThickness = value; 30 | StyleChanged?.Invoke(); 31 | } 32 | } 33 | 34 | public Color ShapeColor 35 | { 36 | get => _shapeColor; 37 | set 38 | { 39 | _shapeColor = value; 40 | StyleChanged?.Invoke(); 41 | } 42 | } 43 | 44 | public Color BackgroundColor 45 | { 46 | get => _backgroundColor; 47 | set 48 | { 49 | _backgroundColor = value; 50 | StyleChanged?.Invoke(); 51 | } 52 | } 53 | 54 | public float Smoothness 55 | { 56 | get => _smoothness; 57 | set 58 | { 59 | _smoothness = value; 60 | StyleChanged?.Invoke(); 61 | } 62 | } 63 | 64 | public event Action StyleChanged; 65 | 66 | public ShapeStyle() { } 67 | 68 | public ShapeStyle(float thickness, float innerThickness, Color shapeColor, Color backgroundColor, float smoothness) 69 | { 70 | _thickness = thickness; 71 | _innerThickness = innerThickness; 72 | _shapeColor = shapeColor; 73 | _backgroundColor = backgroundColor; 74 | _smoothness = smoothness; 75 | } 76 | 77 | public void ApplyToShader(ShaderMaterial material) 78 | { 79 | material.SetShaderParameter("thickness", _thickness); 80 | material.SetShaderParameter("inner_thickness", _innerThickness); 81 | material.SetShaderParameter("shape_color", _shapeColor); 82 | material.SetShaderParameter("background_color", _backgroundColor); 83 | material.SetShaderParameter("smoothness", _smoothness); 84 | } 85 | 86 | public ShapeStyle Clone() 87 | { 88 | return new ShapeStyle(_thickness, _innerThickness, _shapeColor, _backgroundColor, _smoothness); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /TestScenes/Graph/GraphTest.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools; 3 | using PrimerTools.Graph; 4 | 5 | namespace ToolsTestingPlayground.TestScenes; 6 | 7 | [Tool] 8 | public partial class GraphTest : AnimationSequence 9 | { 10 | protected override void Define() 11 | { 12 | #region MyRegion 13 | 14 | var graph = Graph.CreateInstance(); 15 | AddChild(graph); 16 | 17 | graph.Position = Vector3.Left; 18 | graph.XAxis.length = 5; 19 | graph.XAxis.ShowTicCylinders = false; 20 | graph.XAxis.ShowArrows = false; 21 | graph.XAxis.ShowRod = false; 22 | graph.YAxis.Max = 100; 23 | graph.YAxis.TicStep = 20; 24 | graph.YAxis.length = 2; 25 | graph.YAxis.Visible = false; 26 | // graph.YAxis.showTicCylinders = false; 27 | // graph.YAxis.showArrows = false; 28 | graph.ZAxis.length = 0; 29 | graph.Transition(); 30 | 31 | var barPlot = graph.AddBarPlot(); 32 | barPlot.ShowValuesOnBars = true; 33 | barPlot.SetData(10, 20, 30); 34 | RegisterAnimation(graph.Transition()); 35 | 36 | graph.XAxis.length = 4; 37 | barPlot.SetData(20, 30, 10); 38 | RegisterAnimation(graph.Transition()); 39 | 40 | // Point data test 41 | // var data = new PointData(); 42 | // graph.AddChild(data); 43 | // data.AddPoints( 44 | // new Vector3(4, 50, 0), 45 | // new Vector3(1, 80, 0) 46 | // ); 47 | // data.SetData( 48 | // new Vector3(6, 90, 0), 49 | // new Vector3(3, 20, 0) 50 | // ); 51 | // RegisterAnimation(data.Transition()); 52 | 53 | // graph.XAxis.length = 7; 54 | // graph.YAxis.max = 120; 55 | // graph.XAxis.max = 12; 56 | // graph.ZAxis.length = 0; 57 | 58 | // var line = graph.AddLine(); 59 | // line.SetInitialData( 60 | // new Vector3(0, 10, 0) 61 | // ); 62 | 63 | // RegisterAnimation(graph.Transition(0.5f)); 64 | // line.SetColor(PrimerColor.blue); 65 | // graph.XAxis.length = 7; 66 | // graph.YAxis.max = 80; 67 | // graph.XAxis.max = 12; 68 | // graph.ZAxis.length = 0; 69 | 70 | // line.SetData( 71 | // new Vector3(0, 70, 0), 72 | // new Vector3(1, 50, -10), 73 | // new Vector3(2, 0, -20), 74 | // new Vector3(3, 30, -30), 75 | // new Vector3(3, 100, -40), 76 | // new Vector3(2, 100, -50) 77 | // ); 78 | // line.SetData( 79 | // new Vector3(0, 10, 0), 80 | // new Vector3(1, 50, 0) 81 | // // new Vector3(3, 50, 0) 82 | // ); 83 | 84 | // RegisterAnimation(graph.Transition(duration: 5)); 85 | 86 | // line.SetData( 87 | // new Vector3(0, 0, 0), 88 | // new Vector3(1, 50, 0), 89 | // new Vector3(3, 100, 0) 90 | // ); 91 | // 92 | // RegisterAnimation(graph.Update()); 93 | 94 | #endregion 95 | } 96 | } -------------------------------------------------------------------------------- /LaTeX/CLI/LatexInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.Serialization; 5 | 6 | namespace PrimerTools.Latex 7 | { 8 | public sealed record LatexInput(string code, List headers) : ISerializable 9 | { 10 | public static LatexInput From(string code) => new(code, GetDefaultHeaders()); 11 | 12 | public int GetDeterministicHashCode() 13 | { 14 | return $"{code}_${string.Join(',', headers)}".GetDeterministicHashCode(); 15 | } 16 | 17 | public bool Equals(LatexInput other) 18 | { 19 | return other != null 20 | && code == other.code 21 | // We compare them with == because we want to know if both of them are null 22 | // or both o them are the same object, in both cases we don't compare their content 23 | // ReSharper disable once PossibleUnintendedReferenceComparison 24 | && (headers == other.headers || headers.SequenceEqual(other.headers)); 25 | } 26 | 27 | public override int GetHashCode() 28 | { 29 | var hash = new HashCode(); 30 | hash.Add(code); 31 | 32 | for (var i = 0; i < headers.Count; i++) 33 | hash.Add(headers[i]); 34 | 35 | return hash.ToHashCode(); 36 | } 37 | 38 | public void GetObjectData(SerializationInfo info, StreamingContext context) 39 | { 40 | info.AddValue(nameof(code), code); 41 | info.AddValue(nameof(headers), headers); 42 | } 43 | 44 | public static List GetDefaultHeaders() => new() { 45 | @"\documentclass[preview]{standalone}", 46 | @"\usepackage[english]{babel}", 47 | @"\usepackage[utf8]{inputenc}", 48 | @"\usepackage[T1]{fontenc}", 49 | @"\usepackage{amsmath}", 50 | @"\usepackage{amssymb}", 51 | @"\usepackage{dsfont}", 52 | @"\usepackage{setspace}", 53 | @"\usepackage{tipa}", 54 | @"\usepackage{relsize}", 55 | @"\usepackage{textcomp}", 56 | @"\usepackage{mathrsfs}", 57 | @"\usepackage{calligra}", 58 | @"\usepackage{wasysym}", 59 | @"\usepackage{ragged2e}", 60 | @"\usepackage{physics}", 61 | @"\usepackage{xcolor}", 62 | @"\usepackage{microtype}", 63 | @"\usepackage{pifont}", 64 | @"\linespread{1}", 65 | @"\usepackage{concmath-otf}", 66 | @"\usepackage{enumitem}" 67 | }; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Components/AreaPhysicsComponent.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation; 4 | 5 | public struct AreaPhysicsComponent : IComponent 6 | { 7 | public EntityId EntityId { get; set; } 8 | public Transform3D Transform; 9 | 10 | public Vector3 Position 11 | { 12 | get => Transform.Origin; 13 | set => Transform = Transform.Translated(value - Transform.Origin); 14 | } 15 | public Quaternion Quaternion 16 | { 17 | get => Transform.Basis.GetRotationQuaternion(); 18 | set => Transform = new Transform3D(new Basis(value), Transform.Origin); 19 | } 20 | 21 | public float VelocityDampingFactor; 22 | public float AngularVelocityDampingFactor; 23 | 24 | public Vector3 Velocity; 25 | public Vector3 AngularVelocity; 26 | public AreaComponent Body; 27 | public AreaComponent Awareness; 28 | 29 | public AreaPhysicsComponent(Rid space, Vector3 position, Shape3D bodyShape, Vector3 bodyOffset = default) 30 | : this(space, Transform3D.Identity.Translated(position), bodyShape, bodyOffset) {} 31 | 32 | public AreaPhysicsComponent( 33 | Rid space, 34 | Transform3D transform, 35 | Shape3D bodyShape, 36 | Vector3 bodyOffset = default, 37 | float velocityDampingFactor = 0.99f, 38 | float angularVelocityDampingFactor = 0.99f 39 | ) : this() 40 | { 41 | Transform = transform; 42 | Velocity = Vector3.Zero; 43 | Body.Initialize(space, Transform, Transform3D.Identity.Translated(bodyOffset), 44 | bodyShape); 45 | 46 | VelocityDampingFactor = velocityDampingFactor; 47 | AngularVelocityDampingFactor = angularVelocityDampingFactor; 48 | } 49 | 50 | public void AddAwareness(Rid space, float awarenessRadius, Vector3 awarenessOffset = 51 | default) 52 | { 53 | Awareness.Initialize( 54 | space, 55 | Transform, 56 | Transform3D.Identity.Translated(awarenessOffset), 57 | new SphereShape3D { Radius = awarenessRadius } 58 | ); 59 | } 60 | 61 | public Rid GetBodyRid() 62 | { 63 | return Body.Area; 64 | } 65 | 66 | public void CleanUp() 67 | { 68 | Body.CleanUp(); 69 | Awareness.CleanUp(); 70 | } 71 | 72 | public void UpdateCollisionAreas() 73 | { 74 | if (Body.Area != default) 75 | { 76 | Body.UpdateTransform(Transform); 77 | } 78 | if (Awareness.Area != default) 79 | { 80 | Awareness.UpdateTransform(Transform); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/TreeSim/Visual/TreeVisualEntity.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools.Simulation.Components; 3 | 4 | namespace PrimerTools.Simulation.Visual; 5 | 6 | public partial class TreeVisualEntity : VisualEntity 7 | { 8 | public override void Update(EntityRegistry registry) 9 | { 10 | if (!registry.TryGetComponent(EntityId, out var tree)) 11 | return; 12 | 13 | if (tree is { HasFruit: false } && tree.FruitGrowthProgress > FruitTreeSimSettings.NodeFruitGrowthDelay) 14 | { 15 | GrowFruit(FruitTreeSimSettings.FruitGrowthTime - FruitTreeSimSettings.NodeFruitGrowthDelay); 16 | } 17 | 18 | Scale = ScaleFromAge(tree.Age); 19 | } 20 | 21 | // Lazy thing. Gives visual trees an rng object for rotating mangoes. 22 | // Could pass an rng value if we wanted the visual part of the sim to be reliable. 23 | public static Rng NodeTreeRng = new Rng(0); 24 | 25 | private FruitTree _fruitTree; 26 | #region Core methods 27 | public override void _Ready() 28 | { 29 | base._Ready(); 30 | _fruitTree = FruitTree.CreateInstance(); 31 | _fruitTree.Rng = NodeTreeRng; 32 | AddChild(_fruitTree); 33 | Name = "Tree"; 34 | } 35 | public override void Initialize(EntityRegistry registry, EntityId entityId) 36 | { 37 | base.Initialize(registry, entityId); 38 | 39 | if (registry.TryGetComponent(entityId, out var tree)) 40 | { 41 | Scale = ScaleFromAge(tree.Age); 42 | Transform = tree.Body.Transform; 43 | } 44 | } 45 | 46 | private static Vector3 ScaleFromAge(float age) 47 | { 48 | return Vector3.One * Mathf.Min(1, age / FruitTreeSimSettings.TreeMaturationTime); 49 | } 50 | 51 | public Tween TweenToCorrectScale(float age, float duration) 52 | { 53 | var tween = CreateTween(); 54 | tween.TweenProperty( 55 | this, 56 | "scale", 57 | ScaleFromAge(age), 58 | duration 59 | ); 60 | return tween; 61 | } 62 | 63 | public void Death() 64 | { 65 | // GD.Print($"Killing tree {Name}"); 66 | Visible = false; 67 | QueueFree(); 68 | } 69 | #endregion 70 | 71 | #region Behaviors and helpers 72 | public void GrowFruit(double duration) 73 | { 74 | _fruitTree.GrowFruitTween(0, duration / SimulationWorld.TimeScale); 75 | } 76 | public void DestroyFruit() 77 | { 78 | var fruit = _fruitTree.GetFruit(0); 79 | if (fruit == null) return; 80 | fruit.Scale = Vector3.Zero; 81 | } 82 | public Node3D GetFruit() 83 | { 84 | return _fruitTree.GetFruit(0); 85 | } 86 | public bool HasFruit 87 | { 88 | get 89 | { 90 | var fruit = _fruitTree.GetFruit(0); 91 | return fruit != null && _fruitTree.IsFruitOnFlower(fruit); 92 | } 93 | } 94 | #endregion 95 | } -------------------------------------------------------------------------------- /Animation/RigidBodyEnsemble.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Godot; 3 | using PrimerTools; 4 | 5 | /// 6 | /// Meant for objects that need both keyframed movements AND physics movement via rigidbody. 7 | /// RigidBodyEnsemble should have children that are RigidBodies. 8 | /// The class overrides Node3D animation extensions, passing the animations to the RigidBody children instead, 9 | /// allowing us to treat the ensembles as if they were being keyframed without actually keyframing them, 10 | /// which would break the physics calculations (somehow) when the RigidBodies are unfrozen. 11 | /// 12 | public partial class RigidBodyEnsemble : Node3D 13 | { 14 | public Animation MoveTo(Vector3 destination, float duration = 0.5f, bool global = false) 15 | { 16 | var rigidChildren = GetChildren().OfType().ToArray(); 17 | var childDestinations = new Vector3[rigidChildren.Length]; 18 | 19 | var finalGlobalTransformation = new Transform3D( 20 | GlobalTransform.Basis, // Same rotation 21 | destination // New position 22 | ); 23 | if (!global) 24 | { 25 | GD.PushWarning("Local rigidbody movement is untested."); 26 | var finalLocalTransformation = new Transform3D( 27 | Transform.Basis, // Same rotation 28 | destination // New position 29 | ); 30 | finalGlobalTransformation = GetParent().GlobalTransform * finalLocalTransformation; 31 | global = true; 32 | } 33 | 34 | for (var i = 0; i < rigidChildren.Length; i++) 35 | { 36 | childDestinations[i] = (finalGlobalTransformation * rigidChildren[i].Transform).Origin; 37 | } 38 | 39 | return rigidChildren.Select((x, i) => x.MoveToAnimation(childDestinations[i], duration: duration, global: global)) 40 | .InParallel(); 41 | } 42 | 43 | public Animation ScaleTo(Vector3 finalScale, float duration = 0.5f) 44 | { 45 | var rigidChildren = GetChildren().OfType(); 46 | return rigidChildren.Select(x => x.ScaleToAnimation(finalScale, duration: duration)).InParallel(); 47 | } 48 | public Animation ScaleTo(float finalScale, float duration = 0.5f) 49 | { 50 | return ScaleTo(Vector3.One * finalScale, duration); 51 | } 52 | 53 | public virtual Animation Break(float duration = 0.5f, bool forever = false) 54 | { 55 | var rigidChildren = GetChildren().OfType(); 56 | // This should always reset to ensure the rigidbody is frozen when the animation starts playing. 57 | // But if 'forever', just re-freeze after 1000s but correct the animation's Length property. 58 | var animation = rigidChildren.Select(x => x.AnimateFreeze(false, resetAtEnd: true, duration: forever ? 1000 : duration)).InParallel(); 59 | animation.Length = duration; 60 | return animation; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /TestScenes/Latex/LatexAnimationTest.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | using System.Collections.Generic; 4 | using PrimerTools; 5 | using PrimerTools.LaTeX; 6 | 7 | [Tool] 8 | public partial class LatexAnimationTest : AnimationSequence 9 | { 10 | [Export] private int index; 11 | protected override void Define() 12 | { 13 | var latexAnimator = new LatexAnimator(); 14 | AddChild(latexAnimator); 15 | 16 | // latexAnimator.AddExpression("$f(x) = x \\cdot x$"); 17 | // latexAnimator.AddExpression("$f(x) = x^2$"); 18 | 19 | // latexAnimator.AddExpression("$f(x) = x^2$"); 20 | // latexAnimator.AddExpression("$f(g(x)) = (g(x))^2$"); 21 | 22 | var firstExpression = new LatexNode("$f(x) = x^2$"); 23 | firstExpression.HorizontalAlignment = LatexNode.HorizontalAlignmentOptions.Left; 24 | firstExpression.VerticalAlignment = LatexNode.VerticalAlignmentOptions.Baseline; 25 | 26 | var secondExpression = new LatexNode("$f(g(x)) = (g(x))^2$"); 27 | secondExpression.HorizontalAlignment = LatexNode.HorizontalAlignmentOptions.Center; 28 | secondExpression.VerticalAlignment = LatexNode.VerticalAlignmentOptions.Center; 29 | 30 | var thirdExpression = new LatexNode("$f(h(x)) = (h(x))^2$"); 31 | thirdExpression.HorizontalAlignment = LatexNode.HorizontalAlignmentOptions.Right; 32 | thirdExpression.VerticalAlignment = LatexNode.VerticalAlignmentOptions.Top; 33 | 34 | latexAnimator.AddExpression(firstExpression); 35 | latexAnimator.AddExpression(secondExpression); 36 | latexAnimator.AddExpression(thirdExpression); 37 | 38 | var testAnimation = latexAnimator.AnimateToExpression( 39 | 1, 40 | new List<(int currentExpressionChunkBeginIndex, int nextExpressionChunkBeginIndex, int chunkLength)>() 41 | { 42 | // (0, 0, 6) // For the simple test 43 | (0, 0, 2), 44 | (3, 6, 2), 45 | (6, 14, 1) 46 | } 47 | ); 48 | RegisterAnimation(testAnimation); 49 | 50 | var testAnimation2 = latexAnimator.AnimateToExpression( 51 | 2, 52 | new List<(int currentExpressionChunkBeginIndex, int nextExpressionChunkBeginIndex, int chunkLength)>() 53 | { 54 | (0, 0, 2), 55 | (3, 3, 6), 56 | (10, 10, 5) 57 | } 58 | ); 59 | RegisterAnimation(testAnimation2); 60 | 61 | // RegisterAnimation(latexAnimator.AnimateValue(1, LatexAnimator.PropertyName.CurrentExpressionIndex)); 62 | 63 | this.MakeSelfAndChildrenLocal(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Extensions/FloatExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Godot; 5 | 6 | namespace PrimerTools 7 | { 8 | public static class FloatExtensions 9 | { 10 | public static bool IsInteger(this float value) => value % 1 == 0; 11 | public static float GetDecimals(this float value) => value % 1; 12 | 13 | 14 | public static string FormatRoundedToInt(this float number) => $"{number:N0}"; 15 | public static string FormatNumberWithDecimals(this float number) => number == 0 ? "0" : $"{number:0.##}"; 16 | 17 | public static IEnumerable ToFloats(this IEnumerable self) 18 | { 19 | return self.Select(i => i); 20 | } 21 | 22 | public static float[] ToFloatArray(this IEnumerable self) 23 | { 24 | return self.ToFloats().ToArray(); 25 | } 26 | 27 | public static string FormatRoundedToIntForLatexApproxIfRoundsToZero(this float number) 28 | { 29 | var formatted = number.FormatRoundedToInt(); 30 | 31 | // This method should only change the formatting if 32 | if (formatted != "0" || number == 0) 33 | return formatted; 34 | 35 | return @"\sim" + formatted; 36 | } 37 | public static string FormatSignificantDigits(this float number, int significantDigits, int? maxDigitsAfterDecimalPoint = null) 38 | { 39 | if (number == 0) 40 | { 41 | return "0"; 42 | } 43 | 44 | // Determine if decimal point is needed. 45 | float scale = Mathf.Floor(Mathf.Log(Mathf.Abs(number)) / Mathf.Log(10)); 46 | int decimalPlacesNeeded = significantDigits - (int)(scale + 1); 47 | 48 | // Ensure decimalPlacesNeeded isn't negative. 49 | decimalPlacesNeeded = Mathf.Max(0, decimalPlacesNeeded); 50 | 51 | // Check if maxDigitsAfterDecimalPoint is set and less than decimalPlacesNeeded 52 | bool maxDigitsLimitReached = maxDigitsAfterDecimalPoint.HasValue && maxDigitsAfterDecimalPoint.Value < decimalPlacesNeeded; 53 | 54 | if (maxDigitsLimitReached) 55 | { 56 | decimalPlacesNeeded = maxDigitsAfterDecimalPoint.Value; 57 | } 58 | 59 | string format = "{0:F" + decimalPlacesNeeded + "}"; 60 | string result = string.Format(format, number); 61 | 62 | // Prepend "~" if maxDigitsLimitReached 63 | if (maxDigitsLimitReached) 64 | { 65 | result = "~" + result; 66 | } 67 | 68 | return result; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Graph/Resources/YAxisTickNoCylinder.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &187056146824139349 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 8357812543909439236} 12 | - component: {fileID: 149202112628198518} 13 | - component: {fileID: -7583145840370259649} 14 | m_Layer: 0 15 | m_Name: YAxisTickNoCylinder 16 | m_TagString: Untagged 17 | m_Icon: {fileID: 0} 18 | m_NavMeshLayer: 0 19 | m_StaticEditorFlags: 0 20 | m_IsActive: 1 21 | --- !u!4 &8357812543909439236 22 | Transform: 23 | m_ObjectHideFlags: 0 24 | m_CorrespondingSourceObject: {fileID: 0} 25 | m_PrefabInstance: {fileID: 0} 26 | m_PrefabAsset: {fileID: 0} 27 | m_GameObject: {fileID: 187056146824139349} 28 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 29 | m_LocalPosition: {x: 0, y: 0, z: 0} 30 | m_LocalScale: {x: 1, y: 1, z: 1} 31 | m_ConstrainProportionsScale: 0 32 | m_Children: [] 33 | m_Father: {fileID: 0} 34 | m_RootOrder: 0 35 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 36 | --- !u!114 &149202112628198518 37 | MonoBehaviour: 38 | m_ObjectHideFlags: 0 39 | m_CorrespondingSourceObject: {fileID: 0} 40 | m_PrefabInstance: {fileID: 0} 41 | m_PrefabAsset: {fileID: 0} 42 | m_GameObject: {fileID: 187056146824139349} 43 | m_Enabled: 1 44 | m_EditorHideFlags: 0 45 | m_Script: {fileID: 11500000, guid: 89776836f8994f0e94004c7d88ee7f88, type: 3} 46 | m_Name: 47 | m_EditorClassIdentifier: 48 | value: 0 49 | --- !u!114 &-7583145840370259649 50 | MonoBehaviour: 51 | m_ObjectHideFlags: 0 52 | m_CorrespondingSourceObject: {fileID: 0} 53 | m_PrefabInstance: {fileID: 0} 54 | m_PrefabAsset: {fileID: 0} 55 | m_GameObject: {fileID: 187056146824139349} 56 | m_Enabled: 1 57 | m_EditorHideFlags: 0 58 | m_Script: {fileID: 11500000, guid: b8219815f9854ee5b55ea8f92992bb95, type: 3} 59 | m_Name: 60 | m_EditorClassIdentifier: 61 | activeDisplay: {fileID: 0} 62 | _latex: 63 | _headers: 64 | - \documentclass[preview]{standalone} 65 | - \usepackage[english]{babel} 66 | - \usepackage[utf8]{inputenc} 67 | - \usepackage[T1]{fontenc} 68 | - \usepackage{amsmath} 69 | - \usepackage{amssymb} 70 | - \usepackage{dsfont} 71 | - \usepackage{setspace} 72 | - \usepackage{tipa} 73 | - \usepackage{relsize} 74 | - \usepackage{textcomp} 75 | - \usepackage{mathrsfs} 76 | - \usepackage{calligra} 77 | - \usepackage{wasysym} 78 | - \usepackage{ragged2e} 79 | - \usepackage{physics} 80 | - \usepackage{xcolor} 81 | - \usepackage{microtype} 82 | - \usepackage{pifont} 83 | - \linespread{1} 84 | - \usepackage{concmath-otf} 85 | - \usepackage{enumitem} 86 | -------------------------------------------------------------------------------- /Graph/Resources/AxisArrow.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &2477842104010458270 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 1456995410002982541} 12 | - component: {fileID: 7594000412887551163} 13 | - component: {fileID: 4206298620776869954} 14 | m_Layer: 0 15 | m_Name: AxisArrow 16 | m_TagString: Untagged 17 | m_Icon: {fileID: 0} 18 | m_NavMeshLayer: 0 19 | m_StaticEditorFlags: 0 20 | m_IsActive: 1 21 | --- !u!4 &1456995410002982541 22 | Transform: 23 | m_ObjectHideFlags: 0 24 | m_CorrespondingSourceObject: {fileID: 0} 25 | m_PrefabInstance: {fileID: 0} 26 | m_PrefabAsset: {fileID: 0} 27 | m_GameObject: {fileID: 2477842104010458270} 28 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 29 | m_LocalPosition: {x: -0, y: 0, z: 0} 30 | m_LocalScale: {x: 0.07, y: 0.07, z: 0.07} 31 | m_ConstrainProportionsScale: 0 32 | m_Children: [] 33 | m_Father: {fileID: 0} 34 | m_RootOrder: 0 35 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 36 | --- !u!33 &7594000412887551163 37 | MeshFilter: 38 | m_ObjectHideFlags: 0 39 | m_CorrespondingSourceObject: {fileID: 0} 40 | m_PrefabInstance: {fileID: 0} 41 | m_PrefabAsset: {fileID: 0} 42 | m_GameObject: {fileID: 2477842104010458270} 43 | m_Mesh: {fileID: -4024815646192214970, guid: f9ce5fd829f0d44a198abe5e5d3cdc36, type: 3} 44 | --- !u!23 &4206298620776869954 45 | MeshRenderer: 46 | m_ObjectHideFlags: 0 47 | m_CorrespondingSourceObject: {fileID: 0} 48 | m_PrefabInstance: {fileID: 0} 49 | m_PrefabAsset: {fileID: 0} 50 | m_GameObject: {fileID: 2477842104010458270} 51 | m_Enabled: 1 52 | m_CastShadows: 1 53 | m_ReceiveShadows: 1 54 | m_DynamicOccludee: 1 55 | m_StaticShadowCaster: 0 56 | m_MotionVectors: 1 57 | m_LightProbeUsage: 1 58 | m_ReflectionProbeUsage: 1 59 | m_RayTracingMode: 2 60 | m_RayTraceProcedural: 0 61 | m_RenderingLayerMask: 1 62 | m_RendererPriority: 0 63 | m_Materials: 64 | - {fileID: 2100000, guid: 39b41700b9df78e4988dca4de8fe4787, type: 2} 65 | m_StaticBatchInfo: 66 | firstSubMesh: 0 67 | subMeshCount: 0 68 | m_StaticBatchRoot: {fileID: 0} 69 | m_ProbeAnchor: {fileID: 0} 70 | m_LightProbeVolumeOverride: {fileID: 0} 71 | m_ScaleInLightmap: 1 72 | m_ReceiveGI: 1 73 | m_PreserveUVs: 0 74 | m_IgnoreNormalsForChartDetection: 0 75 | m_ImportantGI: 0 76 | m_StitchLightmapSeams: 1 77 | m_SelectedEditorRenderState: 3 78 | m_MinimumChartSize: 4 79 | m_AutoUVMaxDistance: 0.5 80 | m_AutoUVMaxAngle: 89 81 | m_LightmapParameters: {fileID: 0} 82 | m_SortingLayerID: 0 83 | m_SortingLayer: 0 84 | m_SortingOrder: 0 85 | m_AdditionalVertexStreams: {fileID: 0} 86 | -------------------------------------------------------------------------------- /Graph/TernaryGraphWithBars.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Godot; 4 | 5 | namespace PrimerTools.Graph; 6 | 7 | public partial class TernaryGraphWithBars : TernaryGraph 8 | { 9 | [Export] public int BarsPerSide = 10; 10 | 11 | private PackedScene hexagonalPrismScene = 12 | ResourceLoader.Load("res://addons/PrimerTools/Graph/hexagonal_prism.tscn"); 13 | 14 | public float[] Data; 15 | private Node3D[] bars; 16 | 17 | // We need to fit 1 less than the number of bars into the range from 0 to 1 18 | // Also, 1 is the default diameter from corner to corner in the cylinder mesh, 19 | // So need to do the sqrt 3 thing to make the sides touch. 20 | private float BarWidthScale => 1f / (BarsPerSide - 1) / (Mathf.Sqrt(3) / 2) / 2; 21 | public int TotalNumberOfBars => BarsPerSide * (BarsPerSide + 1) / 2; 22 | 23 | private void MakeBarsConsideringTheParameters(float a, float b, float c, int k) 24 | { 25 | bars ??= new Node3D[TotalNumberOfBars]; 26 | 27 | Node3D bar; 28 | if (bars[k] is not null) 29 | { 30 | bar = bars[k]; 31 | } 32 | else 33 | { 34 | bar = MakeBar(); 35 | AddChild(bar); 36 | bars[k] = bar; 37 | } 38 | 39 | bar.Position = CoordinatesToPosition(a, b, c); 40 | var mat = new StandardMaterial3D(); 41 | mat.AlbedoColor = PrimerColor.MixColorsByWeight( 42 | colors: Colors.ToArray(), 43 | new []{ a, b, c } 44 | // subtractive: true, 45 | // messWithBrightness: true 46 | ); 47 | 48 | bar.GetNode("Cylinder").Mesh.SurfaceSetMaterial(0, mat); 49 | bar.RotationDegrees = new Vector3(90, 0, 0); 50 | 51 | bar.Scale = Vector3.Zero; //new Vector3(widthScale, Data[k], widthScale); 52 | } 53 | 54 | public void AddBars() 55 | { 56 | IterateOverTriangleWithNumUnitsPerSide(BarsPerSide, MakeBarsConsideringTheParameters); 57 | } 58 | 59 | private Node3D MakeBar() 60 | { 61 | var bar = hexagonalPrismScene.Instantiate(); 62 | var meshInstance3D = bar.GetNode("Cylinder"); 63 | var newMesh = (Mesh)bar.GetNode("Cylinder").Mesh.Duplicate(); 64 | meshInstance3D.Mesh = newMesh; 65 | 66 | return bar; 67 | } 68 | 69 | public Animation Transition() 70 | { 71 | var animations = new List(); 72 | for (var i = 0; i < TotalNumberOfBars; i++) 73 | { 74 | animations.Add(bars[i].ScaleToAnimation( new Vector3(BarWidthScale, Mathf.Max(Data[i], 0.001f), BarWidthScale))); 75 | } 76 | return animations.InParallel(); 77 | } 78 | } -------------------------------------------------------------------------------- /Graph/Testing/StackedBarPlotTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Godot; 3 | using PrimerTools.Graph; 4 | 5 | [Tool] 6 | public partial class StackedBarPlotTest : Node3D 7 | { 8 | private bool _run; 9 | [Export] 10 | public bool Run 11 | { 12 | get => _run; 13 | set 14 | { 15 | _run = value; 16 | if (value) 17 | { 18 | // Clear any existing children 19 | foreach (var child in GetChildren()) 20 | { 21 | child.Free(); 22 | } 23 | 24 | CreateGraph(); 25 | } 26 | } 27 | } 28 | 29 | private async void CreateGraph() 30 | { 31 | // Create the graph 32 | var graph = Graph.CreateInstance(); 33 | AddChild(graph); 34 | 35 | // Configure the axes 36 | graph.XAxis.length = 10; 37 | graph.YAxis.length = 10; 38 | graph.ZAxis.length = 0; 39 | 40 | graph.XAxis.Max = 5; 41 | graph.YAxis.Max = 10; 42 | graph.ZAxis.Max = 5; 43 | 44 | graph.XAxis.TicStep = 1; 45 | graph.YAxis.TicStep = 2; 46 | graph.ZAxis.TicStep = 1; 47 | graph.Transition(); 48 | 49 | // Create the stacked bar plot 50 | var stackedBarPlot = graph.AddStackedBarPlot(); 51 | 52 | // Create sample data sets 53 | var data1 = new List> 54 | { 55 | new List { 1.0f, 2.0f, 3.0f }, // First stack (bottom to top) 56 | new List { 2.0f, 1.0f, 2.0f }, // Second stack 57 | new List { 1.0f, 2.0f, 1.0f }, // Third stack 58 | new List { 3.0f, 1.0f, 2.0f }, // Fourth stack 59 | new List { 2.0f, 2.0f, 1.0f } // Fifth stack 60 | }; 61 | 62 | var data2 = new List> 63 | { 64 | new List { 2.0f, 1.0f, 1.0f }, // First stack (bottom to top) 65 | new List { 1.0f, 3.0f, 1.0f }, // Second stack 66 | new List { 2.0f, 2.0f, 2.0f }, // Third stack 67 | new List { 1.0f, 2.0f, 3.0f }, // Fourth stack 68 | new List { 2.0f, 1.0f, 2.0f } // Fifth stack 69 | }; 70 | 71 | var datas = new List>> { data1, data2 }; 72 | 73 | stackedBarPlot.ShowValuesOnBars = true; 74 | stackedBarPlot.BarLabelScaleFactor = 0.6f; 75 | 76 | var index = 0; 77 | while (_run) 78 | { 79 | stackedBarPlot.Data = datas[index++ % datas.Count]; 80 | var tween = stackedBarPlot.TweenTransition(); 81 | await tween.ToSignal(tween, Tween.SignalName.Finished); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /LaTeX/CLI/CliProgram.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Threading; 6 | 7 | namespace PrimerTools.Latex 8 | { 9 | public class CliProgram 10 | { 11 | public class ExecutionResult 12 | { 13 | public int exitCode; 14 | public string stdout; 15 | public string stderr; 16 | } 17 | 18 | 19 | readonly string binaryPath; 20 | public Dictionary EnvVars { get; } = new(); 21 | 22 | public CliProgram(string bin) => binaryPath = bin; 23 | 24 | 25 | public ExecutionResult Execute(string cwd, string[] args, CancellationToken ct) 26 | { 27 | ct.ThrowIfCancellationRequested(); 28 | 29 | using var process = new Process { 30 | StartInfo = CreateStartInfo(args, cwd) 31 | }; 32 | 33 | var wasKilled = WaitForCompletion(ct, process); 34 | 35 | ct.ThrowIfCancellationRequested(); 36 | 37 | if (!wasKilled) { 38 | return new ExecutionResult { 39 | exitCode = process.ExitCode, 40 | stdout = process.StandardOutput.ReadToEnd(), 41 | stderr = process.StandardError.ReadToEnd(), 42 | }; 43 | } 44 | 45 | var stdout = Path.Combine(cwd, "stdout.txt"); 46 | var stderr = Path.Combine(cwd, "stderr.txt"); 47 | 48 | using (var stdoutFile = File.Open(stdout, FileMode.Append)) { 49 | process.StandardOutput.BaseStream.CopyTo(stdoutFile); 50 | } 51 | 52 | using (var stderrFile = File.Open(stderr, FileMode.Append)) { 53 | process.StandardError.BaseStream.CopyTo(stderrFile); 54 | } 55 | 56 | throw new TimeoutException($"Process {binaryPath} was killed."); 57 | } 58 | 59 | private static bool WaitForCompletion(CancellationToken ct, Process process) 60 | { 61 | process.Start(); 62 | 63 | while (!process.HasExited && !ct.IsCancellationRequested) { 64 | process.WaitForExit(200); 65 | } 66 | 67 | var forceStop = !process.HasExited; 68 | if (forceStop) process.Kill(); 69 | 70 | return forceStop; 71 | } 72 | 73 | private ProcessStartInfo CreateStartInfo(string[] args, string cwd) 74 | { 75 | var startInfo = new ProcessStartInfo(binaryPath) { 76 | RedirectStandardOutput = true, 77 | RedirectStandardError = true, 78 | UseShellExecute = false, 79 | WorkingDirectory = cwd, 80 | CreateNoWindow = true, 81 | }; 82 | 83 | foreach (var arg in args) { 84 | startInfo.ArgumentList.Add(arg); 85 | } 86 | 87 | foreach (var dir in EnvVars) { 88 | startInfo.Environment.Add(dir.Key, dir.Value); 89 | } 90 | 91 | return startInfo; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Visual/VisualEntityRegistry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Godot; 4 | 5 | namespace PrimerTools.Simulation; 6 | 7 | public partial class VisualEntityRegistry : Node3D 8 | { 9 | private readonly Dictionary _visualEntities = new(); 10 | private readonly Dictionary> _entityFactories = new(); 11 | 12 | // For entities that don't need factories 13 | public void RegisterEntityType() where T : VisualEntity, new() 14 | { 15 | _entityFactories[typeof(T)] = () => new T(); 16 | } 17 | 18 | // For entities that need factories 19 | public void RegisterEntityType(IVisualEntityFactory factory) where T : IVisualEntity 20 | { 21 | _entityFactories[typeof(T)] = () => factory.CreateInstance(); 22 | } 23 | private readonly EntityRegistry _entityRegistry; 24 | 25 | public VisualEntityRegistry(EntityRegistry entityRegistry) 26 | { 27 | _entityRegistry = entityRegistry; 28 | } 29 | 30 | public void SubscribeToComponentEvents() 31 | where TComponent : struct, IComponent 32 | where TVisualEntity : IVisualEntity 33 | { 34 | var storage = _entityRegistry.GetComponentStorageReader(); 35 | storage.ComponentAdded += (component) => CreateVisualEntity(component.EntityId); 36 | storage.ComponentRemoved += RemoveVisualEntity; 37 | } 38 | 39 | public void CreateVisualEntity(EntityId entityId) where T : IVisualEntity 40 | { 41 | if (!_entityFactories.TryGetValue(typeof(T), out var factory)) 42 | { 43 | throw new InvalidOperationException($"No factory registered for visual entity type {typeof(T)}"); 44 | } 45 | 46 | var visualEntity = factory(); 47 | AddChild(visualEntity.RootNode); 48 | _visualEntities.Add(entityId, visualEntity); 49 | visualEntity.Initialize(_entityRegistry, entityId); 50 | } 51 | 52 | public void RemoveVisualEntity(EntityId entityId) 53 | { 54 | if (_visualEntities.TryGetValue(entityId, out var entity)) 55 | { 56 | // We don't queuefree here. Instead, we let the visual entity handle its own disappearance. 57 | // This could probably be handled in a more robust way, but if we ever fail to make a visual entity 58 | // clean itself up, it will be visually obvious. 59 | // entity.RootNode.QueueFree(); 60 | _visualEntities.Remove(entityId); 61 | } 62 | } 63 | 64 | public void Update() 65 | { 66 | foreach (var visualEntity in _visualEntities.Values) 67 | { 68 | visualEntity.Update(_entityRegistry); 69 | } 70 | } 71 | 72 | 73 | public T GetVisualEntity(EntityId entityId) where T : VisualEntity 74 | { 75 | if (!_visualEntities.TryGetValue(entityId, out var value)) 76 | { 77 | GD.PrintErr("Tried to find visual entity that doesn't exist"); 78 | } 79 | return (T)value; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Utilities/ExportedMemberChangeChecker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using Godot; 5 | 6 | public class ExportedMemberChangeChecker 7 | { 8 | private readonly object _targetObject; 9 | private Dictionary _previousMemberStates; 10 | 11 | public ExportedMemberChangeChecker(object targetObject) 12 | { 13 | _targetObject = targetObject; 14 | _previousMemberStates = new Dictionary(); 15 | InitializeMemberStates(); 16 | } 17 | 18 | private void InitializeMemberStates() 19 | { 20 | var type = _targetObject.GetType(); 21 | 22 | // Initialize fields with [Export] attribute 23 | foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) 24 | { 25 | if (field.GetCustomAttribute() != null) 26 | { 27 | _previousMemberStates["Field:" + field.Name] = field.GetValue(_targetObject); 28 | } 29 | } 30 | 31 | // Initialize properties with [Export] attribute 32 | foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) 33 | { 34 | if (prop.CanRead && prop.GetCustomAttribute() != null) 35 | { 36 | _previousMemberStates["Property:" + prop.Name] = prop.GetValue(_targetObject); 37 | } 38 | } 39 | } 40 | 41 | public bool CheckForChanges() 42 | { 43 | var type = _targetObject.GetType(); 44 | 45 | // Check fields with [Export] attribute 46 | foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) 47 | { 48 | if (field.GetCustomAttribute() != null) 49 | { 50 | var currentValue = field.GetValue(_targetObject); 51 | var previousValue = _previousMemberStates["Field:" + field.Name]; 52 | 53 | if (!Equals(currentValue, previousValue)) 54 | { 55 | _previousMemberStates["Field:" + field.Name] = currentValue; 56 | return true; 57 | } 58 | } 59 | } 60 | 61 | // Check properties with [Export] attribute 62 | foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) 63 | { 64 | if (prop.CanRead && prop.GetCustomAttribute() != null) 65 | { 66 | var currentValue = prop.GetValue(_targetObject); 67 | var previousValue = _previousMemberStates.ContainsKey("Property:" + prop.Name) ? _previousMemberStates["Property:" + prop.Name] : null; 68 | 69 | if (!Equals(currentValue, previousValue)) 70 | { 71 | _previousMemberStates["Property:" + prop.Name] = currentValue; 72 | return true; 73 | } 74 | } 75 | } 76 | 77 | return false; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/General/Components/BodyHandler.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools.Simulation; 4 | 5 | public struct BodyHandler : IPhysicsObjectHandler 6 | { 7 | public Rid Rid { get; private set; } 8 | public Shape3D Shape { get; private set; } 9 | public Transform3D LocalTransform3D { get; private set; } 10 | 11 | public BodyHandler(Rid space, Transform3D transform, Transform3D localTransform3D, Shape3D shape, 12 | uint collisionLayer = 1, uint collisionMask = 1) 13 | { 14 | Rid = PhysicsServer3D.BodyCreate(); 15 | Shape = shape; 16 | PhysicsServer3D.BodySetSpace(Rid, space); 17 | LocalTransform3D = localTransform3D; 18 | PhysicsServer3D.BodySetState(Rid, PhysicsServer3D.BodyState.Transform, transform); 19 | PhysicsServer3D.BodyAddShape(Rid, shape.GetRid()); 20 | PhysicsServer3D.BodySetShapeTransform(Rid, 0, LocalTransform3D); 21 | PhysicsServer3D.BodySetParam(Rid, PhysicsServer3D.BodyParameter.CenterOfMass, LocalTransform3D.Origin); 22 | PhysicsServer3D.BodySetCollisionLayer(Rid, collisionLayer); 23 | PhysicsServer3D.BodySetCollisionMask(Rid, collisionMask); 24 | } 25 | 26 | public void Initialize(Rid space, Transform3D transform, Transform3D localTransform3D, Shape3D shape, uint collisionLayer = 1, uint collisionMask = 1) 27 | { 28 | GD.Print("Consider using the constructor instead"); 29 | var body = PhysicsServer3D.BodyCreate(); 30 | PhysicsServer3D.BodySetSpace(body, space); 31 | LocalTransform3D = localTransform3D; 32 | PhysicsServer3D.BodySetState(body, PhysicsServer3D.BodyState.Transform, transform); 33 | PhysicsServer3D.BodyAddShape(body, shape.GetRid()); 34 | PhysicsServer3D.BodySetShapeTransform(body, 0, LocalTransform3D); 35 | PhysicsServer3D.BodySetParam(body, PhysicsServer3D.BodyParameter.CenterOfMass, LocalTransform3D.Origin); 36 | PhysicsServer3D.BodySetCollisionLayer(body, collisionLayer); 37 | PhysicsServer3D.BodySetCollisionMask(body, collisionMask); 38 | 39 | Rid = body; 40 | Shape = shape; 41 | } 42 | 43 | public void CleanUp() 44 | { 45 | if (Shape != null && Shape.GetReferenceCount() == 1) 46 | { 47 | Shape.Dispose(); 48 | } 49 | if (Rid == default) return; 50 | PhysicsServer3D.FreeRid(Rid); 51 | } 52 | 53 | public void UpdateBaseTransform(Transform3D transform) 54 | { 55 | PhysicsServer3D.BodySetState(Rid, PhysicsServer3D.BodyState.Transform, transform); 56 | } 57 | 58 | public Transform3D Transform =>(Transform3D)PhysicsServer3D.BodyGetState(Rid, PhysicsServer3D.BodyState.Transform); 59 | 60 | public Area3D ConstructDebugNode(Node3D parent) 61 | { 62 | var bodyArea = new Area3D(); 63 | bodyArea.CollisionLayer = 0; 64 | bodyArea.CollisionMask = 0; 65 | parent.AddChild(bodyArea); 66 | var bodyShape = new CollisionShape3D(); 67 | bodyArea.AddChild(bodyShape); 68 | bodyShape.Shape = Shape; 69 | bodyArea.Transform = LocalTransform3D; 70 | return bodyArea; 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /Utilities/PrimerColor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection.Metadata; 5 | using GladiatorManager.addons.PrimerTools; 6 | using Godot; 7 | 8 | namespace PrimerTools; 9 | 10 | public static class PrimerColor 11 | { 12 | public static Color Blue => PrimerConfig.Instance.Colors.Blue; 13 | public static Color Orange => PrimerConfig.Instance.Colors.Orange; 14 | public static Color Yellow => PrimerConfig.Instance.Colors.Yellow; 15 | public static Color Red => PrimerConfig.Instance.Colors.Red; 16 | public static Color Green => PrimerConfig.Instance.Colors.Green; 17 | public static Color Purple => PrimerConfig.Instance.Colors.Purple; 18 | public static Color Gray => PrimerConfig.Instance.Colors.Gray; 19 | public static Color White => PrimerConfig.Instance.Colors.White; 20 | public static Color Black => PrimerConfig.Instance.Colors.Black; 21 | 22 | public static readonly Color[] Rainbow = { 23 | Red, 24 | Orange, 25 | Yellow, 26 | Green, 27 | Blue, 28 | Purple, 29 | }; 30 | 31 | // Color mixing 32 | public static Color JuicyInterpolate(Color a, Color b, float t, float juiciness = 0.5f) 33 | { 34 | GD.PushWarning("JuicyInterpolate is deprecated. Use InterpolateInLinearSpace instead."); 35 | return InterpolateInLinearSpace(a, b, t); 36 | } 37 | public static Color InterpolateInLinearSpace(Color a, Color b, float t) 38 | { 39 | return MixColorsByWeight(new[] { a, b }, new[] { 1 - t, t }); 40 | } 41 | 42 | public static Color OneMinusTheColor(Color theColor) 43 | { 44 | return new Color(1 - theColor.R, 1 - theColor.G, 1 - theColor.B, theColor.A); 45 | } 46 | 47 | public static Color MixColorsByWeight(Color[] colors, float[] weights, bool subtractive = true, bool messWithBrightness = true) 48 | { 49 | float r = 0; 50 | float g = 0; 51 | float b = 0; 52 | float a = 0; 53 | float v = 0; 54 | if (colors.Length != weights.Length) GD.PrintErr($"MixColorsByWeight received arrays of different lengths. Colors: {colors.Length}, Weights: {weights.Length}"); 55 | 56 | var normalizationFactor = weights.Sum(); 57 | 58 | for (var i = 0; i < colors.Length; i++) 59 | { 60 | var color = colors[i]; 61 | 62 | if (subtractive) 63 | { 64 | color = OneMinusTheColor(color); 65 | } 66 | 67 | var linearColor = color.SrgbToLinear(); 68 | r += linearColor.R * weights[i] / normalizationFactor; 69 | g += linearColor.G * weights[i] / normalizationFactor; 70 | b += linearColor.B * weights[i] / normalizationFactor; 71 | a += linearColor.A * weights[i] / normalizationFactor; 72 | v += linearColor.V * weights[i] / normalizationFactor; 73 | } 74 | 75 | var mixedColor = new Color(r, g, b, a); 76 | if (messWithBrightness) { mixedColor.V = v; } 77 | var finalishColor = mixedColor.LinearToSrgb(); 78 | if (subtractive) finalishColor = OneMinusTheColor(finalishColor); 79 | return finalishColor; 80 | } 81 | } -------------------------------------------------------------------------------- /LaTeX/CLI/.idea/.idea.CLI.dir/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 27 | 43 | 44 | 45 | 46 | 47 | 1706202199214 48 | 53 | 54 | 55 | 56 | 58 | 59 | 61 | -------------------------------------------------------------------------------- /Graph/Resources/AxisRod.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &5459745604207397341 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 4773816293130582003} 12 | - component: {fileID: 6584484557646656961} 13 | - component: {fileID: 7896399576522927485} 14 | - component: {fileID: 3369497961167198319} 15 | m_Layer: 0 16 | m_Name: AxisRod 17 | m_TagString: Untagged 18 | m_Icon: {fileID: 0} 19 | m_NavMeshLayer: 0 20 | m_StaticEditorFlags: 0 21 | m_IsActive: 1 22 | --- !u!4 &4773816293130582003 23 | Transform: 24 | m_ObjectHideFlags: 0 25 | m_CorrespondingSourceObject: {fileID: 0} 26 | m_PrefabInstance: {fileID: 0} 27 | m_PrefabAsset: {fileID: 0} 28 | m_GameObject: {fileID: 5459745604207397341} 29 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 30 | m_LocalPosition: {x: 0.036699906, y: -0.5941199, z: 0.1289196} 31 | m_LocalScale: {x: 1, y: 1, z: 1} 32 | m_ConstrainProportionsScale: 0 33 | m_Children: [] 34 | m_Father: {fileID: 0} 35 | m_RootOrder: 0 36 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 37 | --- !u!33 &6584484557646656961 38 | MeshFilter: 39 | m_ObjectHideFlags: 0 40 | m_CorrespondingSourceObject: {fileID: 0} 41 | m_PrefabInstance: {fileID: 0} 42 | m_PrefabAsset: {fileID: 0} 43 | m_GameObject: {fileID: 5459745604207397341} 44 | m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} 45 | --- !u!23 &7896399576522927485 46 | MeshRenderer: 47 | m_ObjectHideFlags: 0 48 | m_CorrespondingSourceObject: {fileID: 0} 49 | m_PrefabInstance: {fileID: 0} 50 | m_PrefabAsset: {fileID: 0} 51 | m_GameObject: {fileID: 5459745604207397341} 52 | m_Enabled: 1 53 | m_CastShadows: 1 54 | m_ReceiveShadows: 1 55 | m_DynamicOccludee: 1 56 | m_StaticShadowCaster: 0 57 | m_MotionVectors: 1 58 | m_LightProbeUsage: 1 59 | m_ReflectionProbeUsage: 1 60 | m_RayTracingMode: 2 61 | m_RayTraceProcedural: 0 62 | m_RenderingLayerMask: 1 63 | m_RendererPriority: 0 64 | m_Materials: 65 | - {fileID: 2100000, guid: 7309bf14761c9794fb48c5f79de8c4e7, type: 2} 66 | m_StaticBatchInfo: 67 | firstSubMesh: 0 68 | subMeshCount: 0 69 | m_StaticBatchRoot: {fileID: 0} 70 | m_ProbeAnchor: {fileID: 0} 71 | m_LightProbeVolumeOverride: {fileID: 0} 72 | m_ScaleInLightmap: 1 73 | m_ReceiveGI: 1 74 | m_PreserveUVs: 0 75 | m_IgnoreNormalsForChartDetection: 0 76 | m_ImportantGI: 0 77 | m_StitchLightmapSeams: 1 78 | m_SelectedEditorRenderState: 3 79 | m_MinimumChartSize: 4 80 | m_AutoUVMaxDistance: 0.5 81 | m_AutoUVMaxAngle: 89 82 | m_LightmapParameters: {fileID: 0} 83 | m_SortingLayerID: 0 84 | m_SortingLayer: 0 85 | m_SortingOrder: 0 86 | m_AdditionalVertexStreams: {fileID: 0} 87 | --- !u!136 &3369497961167198319 88 | CapsuleCollider: 89 | m_ObjectHideFlags: 0 90 | m_CorrespondingSourceObject: {fileID: 0} 91 | m_PrefabInstance: {fileID: 0} 92 | m_PrefabAsset: {fileID: 0} 93 | m_GameObject: {fileID: 5459745604207397341} 94 | m_Material: {fileID: 0} 95 | m_IsTrigger: 0 96 | m_Enabled: 1 97 | m_Radius: 0.5000001 98 | m_Height: 2 99 | m_Direction: 1 100 | m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} 101 | -------------------------------------------------------------------------------- /Simulation/ContinuousSpaceTimeSims/Specific/TreeSim/Visual/FruitVisualEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Godot; 3 | using PrimerTools.Simulation.Components; 4 | 5 | namespace PrimerTools.Simulation.Visual; 6 | 7 | public partial class FruitVisualEntity : VisualEntity 8 | { 9 | private static readonly PackedScene MangoScene = 10 | ResourceLoader.Load("res://addons/PrimerTools/Simulation/Models/Mango/mango.scn"); 11 | 12 | private Node3D _fruitModel; 13 | 14 | public override void _Ready() 15 | { 16 | base._Ready(); 17 | 18 | // Create fruit model 19 | _fruitModel = MangoScene.Instantiate(); 20 | AddChild(_fruitModel); 21 | 22 | // Start with zero scale 23 | _fruitModel.Scale = Vector3.Zero; 24 | 25 | Name = "Fruit"; 26 | } 27 | 28 | public override void Initialize(EntityRegistry registry, EntityId entityId) 29 | { 30 | base.Initialize(registry, entityId); 31 | 32 | if (registry.TryGetComponent(entityId, out var fruit)) 33 | { 34 | Transform = fruit.Body.Transform; 35 | _fruitModel.Scale = Vector3.One * fruit.GrowthProgress; 36 | } 37 | 38 | AddDebugNodes(fruit.Body); 39 | } 40 | 41 | public override void Update(EntityRegistry registry) 42 | { 43 | if (!registry.TryGetComponent(EntityId, out var fruit)) 44 | return; 45 | 46 | // Update transform from physics body 47 | Transform = fruit.Body.Transform; 48 | 49 | // Update scale based on growth progress 50 | _fruitModel.Scale = Vector3.One * fruit.GrowthProgress; 51 | } 52 | 53 | // public void HandleRipened() 54 | // { 55 | // // Visual effect for ripening (could change color or material) 56 | // var material = new StandardMaterial3D(); 57 | // material.AlbedoColor = new Color(1.0f, 0.8f, 0.0f); // More yellow/golden when ripe 58 | // 59 | // // Apply to mesh instance if available 60 | // if (_fruitModel.GetChild(0) is MeshInstance3D meshInstance) 61 | // { 62 | // meshInstance.MaterialOverride = material; 63 | // } 64 | // } 65 | 66 | // public void HandleDetached() 67 | // { 68 | // // Visual effect for detachment (could play animation or particle effect) 69 | // // For now, just rotate slightly to show it's loose 70 | // var tween = CreateTween(); 71 | // tween.TweenProperty( 72 | // _fruitModel, 73 | // "rotation", 74 | // new Vector3(Mathf.DegToRad(15), 0, 0), 75 | // 0.3f 76 | // ); 77 | // } 78 | 79 | public void HandleDecayed() 80 | { 81 | // Do this first because the areas don't like having zero scale 82 | foreach (var areaNode in GetChildren().OfType()) 83 | { 84 | areaNode.QueueFree(); 85 | } 86 | // Visual effect for decay (fade out and remove) 87 | var tween = CreateTween(); 88 | tween.TweenProperty( 89 | this, 90 | "scale", // Alpha channel 91 | Vector3.Zero, 92 | 0.5f 93 | ); 94 | tween.TweenCallback(Callable.From(() => QueueFree())); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /LaTeX/CLI/LatexBinaries.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading; 6 | 7 | namespace PrimerTools.Latex 8 | { 9 | internal static class LatexBinaries 10 | { 11 | // internal static readonly DirectoryInfo rootTempDir; 12 | private const string LatexBinDir = ""; 13 | private const string XelatexDir = ""; 14 | private const string DvisvgmDir = ""; 15 | 16 | public static CliProgram.ExecutionResult Xelatex(TempDir cwd, string[] args, CancellationToken ct) 17 | { 18 | var program = GetCliProgram(XelatexDir, "xelatex"); 19 | return program.Execute(cwd.FullPath, args, ct); 20 | } 21 | 22 | public static CliProgram.ExecutionResult Dvisvgm(TempDir cwd, string[] args, CancellationToken ct) 23 | { 24 | var program = GetCliProgram(DvisvgmDir, "dvisvgm"); 25 | return program.Execute(cwd.FullPath, args, ct); 26 | } 27 | 28 | public static string GetXelatexErrorLogsFrom(TempDir cwd, string filename) 29 | { 30 | var logFile = cwd.GetChildPath(filename); 31 | if (!File.Exists(logFile)) return null; 32 | 33 | var errors = 34 | from line in File.ReadAllLines(logFile) 35 | where line.StartsWith("! ") && line.Length > 2 36 | select line[2..]; 37 | 38 | return string.Join(", ", errors); 39 | } 40 | 41 | 42 | private static CliProgram GetCliProgram(string setting, string filename) 43 | { 44 | var path = GetBinary(setting, filename); 45 | if (string.IsNullOrWhiteSpace(path)) return null; 46 | 47 | var binDir = string.IsNullOrWhiteSpace(LatexBinDir) 48 | ? Path.GetDirectoryName(path) 49 | : LatexBinDir; 50 | 51 | var cli = new CliProgram(path); 52 | cli.EnvVars["PATH"] = binDir; 53 | return cli; 54 | } 55 | 56 | private static string GetBinary(string setting, string filename) 57 | { 58 | if (!string.IsNullOrWhiteSpace(setting)) { 59 | return setting; 60 | } 61 | 62 | if (!string.IsNullOrWhiteSpace(LatexBinDir)) { 63 | var found = FindBinary(LatexBinDir, filename); 64 | if (found is not null) return found; 65 | } 66 | 67 | foreach (var path in PathEnvVar()) { 68 | var found = FindBinary(path, filename); 69 | if (found is not null) return found; 70 | } 71 | 72 | throw new FileNotFoundException($"Could not find {filename} in your PATH. You can configure it in Unity editor preferences."); 73 | } 74 | 75 | private static string FindBinary(string path, string filename) 76 | { 77 | var plain = Path.Combine(path, filename); 78 | if (File.Exists(plain)) return plain; 79 | 80 | var exe = $"{plain}.exe"; 81 | return File.Exists(exe) ? exe : null; 82 | } 83 | 84 | private static IEnumerable PathEnvVar() 85 | { 86 | var delimiter = Path.PathSeparator; 87 | var path = Environment.GetEnvironmentVariable("PATH"); 88 | return path?.Split(delimiter) ?? new string[] {}; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Extensions/MeshInstance3DExtensions.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using PrimerTools.TweenSystem; 3 | 4 | namespace PrimerTools; 5 | 6 | public static class MeshInstance3DExtensions 7 | { 8 | public static StandardMaterial3D GetOrCreateOverrideMaterial(this MeshInstance3D meshInstance3D, int index = 0) 9 | { 10 | // Currently, this creates a new material if there's no existing override. I'm not certain whether this 11 | // is terribly inefficient. I know Godot has inherited materials or something like that, which should be 12 | // more efficient, but I don't know if this uses that under the hood or what. 13 | 14 | // Use the surface material override if it's there and a StandardMaterial3D 15 | var currentOverride = meshInstance3D.GetSurfaceOverrideMaterial(index); 16 | if (currentOverride is StandardMaterial3D material) 17 | { 18 | return material; 19 | } 20 | if (currentOverride != null) 21 | { 22 | // There may be other material types this works for, but just working with StandardMaterial3D for now. 23 | GD.PushWarning($"Surface override material of {meshInstance3D.Name} is not a StandardMaterial3D. " + 24 | $"Haven't handled that case for animations," + 25 | $"so replacing with a new StandardMaterial3D."); 26 | } 27 | 28 | // If not, copy the mesh's material and put it in the override slot to avoid changing the color of all the objects that share the mesh. 29 | // If neither exist, just create a new standard material and put it in the override slot. 30 | var meshMaterial = meshInstance3D.Mesh.SurfaceGetMaterial(index); 31 | var newOverrideMaterial = meshMaterial != null 32 | ? (StandardMaterial3D)meshMaterial.Duplicate() 33 | : new StandardMaterial3D(); 34 | 35 | meshInstance3D.SetSurfaceOverrideMaterial(0, newOverrideMaterial); 36 | return newOverrideMaterial; 37 | } 38 | 39 | public static void SetColorOfAllMaterials(this MeshInstance3D meshInstance3D, Color color) 40 | { 41 | for (var i = 0; i < meshInstance3D.GetSurfaceOverrideMaterialCount(); i++) 42 | { 43 | meshInstance3D.GetOrCreateOverrideMaterial(i).AlbedoColor = color; 44 | } 45 | } 46 | 47 | public static IStateChange FadeOut(this MeshInstance3D meshInstance3D) 48 | { 49 | var mat = meshInstance3D.GetOrCreateOverrideMaterial(); 50 | // Todo: Make some of these options if they ever look bad 51 | mat.Transparency = BaseMaterial3D.TransparencyEnum.Alpha; 52 | mat.CullMode = BaseMaterial3D.CullModeEnum.Back; 53 | mat.DepthDrawMode = BaseMaterial3D.DepthDrawModeEnum.Always; 54 | 55 | var newColor = new Color(mat.AlbedoColor.R, mat.AlbedoColor.G, mat.AlbedoColor.B, 0); 56 | return new PropertyStateChange(mat, "albedo_color", newColor); 57 | 58 | // return new PropertyStateChange(meshInstance3D, "transparency", 1); 59 | } 60 | 61 | public static IStateChange FadeIn(this MeshInstance3D meshInstance3D) 62 | { 63 | var mat = meshInstance3D.GetOrCreateOverrideMaterial(); 64 | 65 | var newColor = new Color(mat.AlbedoColor.R, mat.AlbedoColor.G, mat.AlbedoColor.B, 1); 66 | return new PropertyStateChange(mat, "albedo_color", newColor); 67 | } 68 | } -------------------------------------------------------------------------------- /Utilities/Easing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Godot; 3 | 4 | // Claude wrote these 5 | public static class Easing 6 | { 7 | /// 8 | /// Applies cubic easing to a value between 0 and 1. 9 | /// Values outside this range will be clamped. 10 | /// 11 | /// Input value (ideally between 0 and 1) 12 | /// Eased value between 0 and 1 13 | public static float CubicEaseIn(float t) 14 | { 15 | // Clamp the input value between 0 and 1 16 | t = Math.Clamp(t, 0f, 1f); 17 | 18 | // Apply cubic easing: t³ 19 | return t * t * t; 20 | } 21 | 22 | /// 23 | /// Applies cubic ease-in-out to a value between 0 and 1. 24 | /// Values outside this range will be clamped. 25 | /// 26 | /// Input value (ideally between 0 and 1) 27 | /// Eased value between 0 and 1 28 | public static float CubicEaseInOut(float t) 29 | { 30 | // Clamp the input value between 0 and 1 31 | t = Math.Clamp(t, 0f, 1f); 32 | 33 | // Apply cubic ease-in-out 34 | return t < 0.5 35 | ? 4 * t * t * t 36 | : 1 - Mathf.Pow(-2 * t + 2, 3) / 2; 37 | } 38 | 39 | /// 40 | /// Applies cubic ease-out to a value between 0 and 1. 41 | /// Values outside this range will be clamped. 42 | /// 43 | /// Input value (ideally between 0 and 1) 44 | /// Eased value between 0 and 1 45 | public static float CubicEaseOut(float t) 46 | { 47 | // Clamp the input value between 0 and 1 48 | t = Math.Clamp(t, 0f, 1f); 49 | 50 | // Apply cubic ease-out: 1-(1-t)³ 51 | return 1 - Mathf.Pow(1 - t, 3); 52 | } 53 | 54 | /// 55 | /// Creates an easing function with configurable pauses at the beginning and end. 56 | /// Returns 0 when input is below startThreshold, returns 1 when input is above endThreshold, 57 | /// and performs easing between these thresholds. 58 | /// 59 | /// Input value (ideally between 0 and 1) 60 | /// Value below which the output is 0 (e.g., 0.25) 61 | /// Value above which the output is 1 (e.g., 0.75) 62 | /// The easing function to use between thresholds (defaults to linear) 63 | /// Eased value between 0 and 1 with pauses 64 | public static float EaseWithPause(float t, float startThreshold, float endThreshold, Func easingFunc = null) 65 | { 66 | // Clamp the input value between 0 and 1 67 | t = Math.Clamp(t, 0f, 1f); 68 | 69 | // Default to linear easing if no function provided 70 | easingFunc ??= (x) => x; 71 | 72 | // Handle cases outside the easing range 73 | if (t <= startThreshold) 74 | return 0f; 75 | 76 | if (t >= endThreshold) 77 | return 1f; 78 | 79 | // Normalize t to 0-1 range between thresholds 80 | float normalizedT = (t - startThreshold) / (endThreshold - startThreshold); 81 | 82 | // Apply the provided easing function 83 | return easingFunc(normalizedT); 84 | } 85 | } -------------------------------------------------------------------------------- /PrimerConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text.Json; 4 | using Godot; 5 | 6 | namespace GladiatorManager.addons.PrimerTools; 7 | 8 | public class PrimerConfig 9 | { 10 | // Just a color palette handler at this point 11 | private const string ConfigPath = "res://primer_config.json"; 12 | public ColorPalette Colors { get; set; } 13 | 14 | public PrimerConfig() 15 | { 16 | Colors = new ColorPalette(); 17 | } 18 | 19 | public class ColorPalette 20 | { 21 | public Color Blue { get; set; } = Godot.Colors.DodgerBlue; 22 | public Color Red { get; set; } = Godot.Colors.Crimson; 23 | public Color Green { get; set; } = Godot.Colors.ForestGreen; 24 | public Color Orange { get; set; } = Godot.Colors.DarkOrange; 25 | public Color Purple { get; set; } = Godot.Colors.DarkOrchid; 26 | public Color Yellow { get; set; } = Godot.Colors.Gold; 27 | public Color Gray { get; set; } = Godot.Colors.Gray; 28 | public Color LightGray { get; set; } = Godot.Colors.LightGray; 29 | public Color White { get; set; } = Godot.Colors.White; 30 | public Color Black { get; set; } = Godot.Colors.Black; 31 | } 32 | 33 | private static PrimerConfig _instance; 34 | public static PrimerConfig Instance 35 | { 36 | get 37 | { 38 | if (_instance == null) 39 | { 40 | LoadConfig(); 41 | } 42 | return _instance; 43 | } 44 | } 45 | 46 | private static void LoadConfig(string configPath = ConfigPath) 47 | { 48 | // It's convenient to comment this out when iterating on the palette 49 | // using the default colors above. 50 | // Otherwise, you have to delete the config file between changes. 51 | // return new PrimerConfig(); 52 | 53 | configPath = ProjectSettings.GlobalizePath(configPath); 54 | try 55 | { 56 | // Try to load custom config 57 | string jsonString = File.ReadAllText(configPath); 58 | var options = new JsonSerializerOptions 59 | { 60 | PropertyNameCaseInsensitive = true 61 | }; 62 | 63 | _instance = JsonSerializer.Deserialize(jsonString, options); 64 | } 65 | catch (FileNotFoundException ex) 66 | { 67 | GD.PushWarning($"Config file not found at: {configPath}. Creating default config.", ex); 68 | _instance = new PrimerConfig(); 69 | SaveConfig(); 70 | } 71 | catch (JsonException ex) 72 | { 73 | throw new JsonException($"Error parsing JSON from file: {configPath}", ex); 74 | } 75 | } 76 | 77 | public static void SaveConfig(string configPath = ConfigPath) 78 | { 79 | configPath = ProjectSettings.GlobalizePath(configPath); 80 | try 81 | { 82 | var options = new JsonSerializerOptions 83 | { 84 | WriteIndented = true, 85 | PropertyNamingPolicy = JsonNamingPolicy.CamelCase 86 | }; 87 | 88 | var jsonString = JsonSerializer.Serialize(Instance, options); 89 | File.WriteAllText(configPath, jsonString); 90 | } 91 | catch (Exception ex) 92 | { 93 | throw new Exception($"Failed to save config to {configPath}: {ex.Message}", ex); 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /Utilities/Transform3DUtils.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace PrimerTools; 4 | 5 | public static class Transform3DUtils 6 | { 7 | public static Quaternion QuaternionFromEulerDeg(Vector3 euler) 8 | { 9 | return Quaternion.FromEuler(euler * Mathf.Pi / 180); 10 | } 11 | 12 | public static Basis BasisFromForwardAndUp(Vector3 forward, Vector3 up) 13 | { 14 | var left = up.Cross(forward).Normalized(); 15 | up = forward.Cross(left).Normalized(); // Recompute up to ensure orthogonality 16 | return new Basis(left, up, forward).Orthonormalized(); 17 | } 18 | 19 | public static (Vector3 axis, float angle) GetAxisAngleRotationTowardBasis(this Basis basis, Basis desiredBasis) 20 | { 21 | var currentRotation = basis.GetRotationQuaternion(); 22 | var targetRotation = desiredBasis.GetRotationQuaternion(); 23 | var rotationDifference = targetRotation * currentRotation.Inverse(); 24 | 25 | // Convert to axis-angle representation 26 | var axis = rotationDifference.GetAxis();//.Normalized(); 27 | var angle = rotationDifference.GetAngle(); 28 | if (angle > Mathf.Pi) 29 | { 30 | angle = 2 * Mathf.Pi - angle; 31 | axis = -axis; 32 | } 33 | 34 | return (axis, angle); 35 | } 36 | 37 | public static Vector3 CalculateAngularVelocityTowardBasis(this Transform3D transform, Basis desiredBasis, float rotationSpeedFactor = 10, float maxRotationSpeed = 10) 38 | { 39 | var (axis, angle) = transform.Basis.GetAxisAngleRotationTowardBasis(desiredBasis); 40 | return axis * Mathf.Min(angle * rotationSpeedFactor, maxRotationSpeed); 41 | } 42 | 43 | public static Vector3 CalculateVelocityAcceleratedTowardTarget(Vector3 targetDestination, Vector3 currentPosition, Vector3 currentVelocity, float maxSpeed, float accelerationFactor = 0.1f) 44 | { 45 | var accelerationVector = 46 | CalculateAccelerationTowardTarget(targetDestination, currentPosition, currentVelocity, maxSpeed, accelerationFactor); 47 | var newVelocity = currentVelocity + accelerationVector; 48 | 49 | return newVelocity.LimitLength(maxSpeed); 50 | 51 | } 52 | 53 | public static Vector3 CalculateAccelerationTowardTarget(Vector3 targetDestination, Vector3 currentPosition, Vector3 currentVelocity, float maxSpeed, float accelerationFactor = 0.1f) 54 | { 55 | if (targetDestination == Vector3.Zero) GD.Print("Moving to the origin"); 56 | var desiredDisplacement = targetDestination - currentPosition; 57 | var desiredDisplacementLengthSquared = desiredDisplacement.LengthSquared(); 58 | 59 | var desiredVelocity = Vector3.Zero; 60 | if (desiredDisplacementLengthSquared != 0) 61 | { 62 | desiredVelocity = desiredDisplacement * maxSpeed; 63 | } 64 | 65 | var velocityChange = desiredVelocity - currentVelocity; 66 | var velocityChangeLengthSquared = velocityChange.LengthSquared(); 67 | 68 | var maxAccelerationMagnitudeSquared = maxSpeed * maxSpeed * accelerationFactor * accelerationFactor; 69 | Vector3 accelerationVector; 70 | if (velocityChangeLengthSquared > maxAccelerationMagnitudeSquared) 71 | { 72 | accelerationVector = Mathf.Sqrt(maxAccelerationMagnitudeSquared / velocityChangeLengthSquared) * velocityChange; 73 | } 74 | else 75 | { 76 | accelerationVector = velocityChange; 77 | } 78 | 79 | return accelerationVector; 80 | } 81 | } --------------------------------------------------------------------------------