diff --git a/Nu/Nu.Gaia/Assets/Default/AnimatedModelIcon.png b/Nu/Nu.Gaia/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Nu/Nu.Gaia/Assets/Default/AnimatedModelIcon.png differ diff --git a/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Nu/Nu.Gaia/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Gaia/Assets/Default/RawIcon.png b/Nu/Nu.Gaia/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Nu/Nu.Gaia/Assets/Default/RawIcon.png differ diff --git a/Nu/Nu.Gaia/Assets/Default/SongIcon.png b/Nu/Nu.Gaia/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Nu/Nu.Gaia/Assets/Default/SongIcon.png differ diff --git a/Nu/Nu.Gaia/Assets/Default/SoundIcon.png b/Nu/Nu.Gaia/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Nu/Nu.Gaia/Assets/Default/SoundIcon.png differ diff --git a/Nu/Nu.Gaia/Assets/Default/SpineSkeletonIcon.png b/Nu/Nu.Gaia/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Nu/Nu.Gaia/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Nu/Nu.Gaia/Assets/Default/StaticModelIcon.png b/Nu/Nu.Gaia/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Nu/Nu.Gaia/Assets/Default/StaticModelIcon.png differ diff --git a/Nu/Nu.Gaia/Assets/Default/TileMapIcon.png b/Nu/Nu.Gaia/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Nu/Nu.Gaia/Assets/Default/TileMapIcon.png differ diff --git a/Nu/Nu.Gaia/Gaia.fs b/Nu/Nu.Gaia/Gaia.fs index 3777f51bb2..714893a45f 100644 --- a/Nu/Nu.Gaia/Gaia.fs +++ b/Nu/Nu.Gaia/Gaia.fs @@ -61,7 +61,7 @@ module Gaia = let mutable private PropertyEditorFocusRequested = false let mutable private EntityHierarchySearchRequested = false let mutable private AssetViewerSearchRequested = false - let mutable private DragDropPayloadOpt = None + let mutable private DragDropPayloadOpt = Option.None let mutable private DragEntityState = DragEntityInactive let mutable private DragEyeState = DragEyeInactive let mutable private SelectedScreen = Game / "Screen" // TODO: see if this is necessary or if we can just use World.getSelectedScreen. @@ -111,6 +111,7 @@ module Gaia = let mutable private EntityHierarchySearchStr = "" let mutable private PropagationSourcesSearchStr = "" let mutable private AssetViewerSearchStr = "" + let mutable private LoadPackageName = "" (* Project States *) @@ -831,7 +832,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= (* Editor Command Functions *) let private createRestorePoint world = - World.playSound Constants.Audio.SoundVolumeDefault Assets.Default.Sound world + World.playSound 0.0f 0.0f Constants.Audio.SoundVolumeDefault Assets.Default.Sound world if world.Advancing then World.setAdvancing false world snapshot RestorePoint world @@ -878,15 +879,15 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= else entity.SetTransform entityTransform world if entity.Surnames.Length > 1 then if World.getEntityAllowedToMount entity world then - entity.SetMountOptWithAdjustment (Some Address.parent) world + entity.SetMountOptWithAdjustment true (Some Address.parent) world match entity.TryGetProperty (nameof entity.ProbeBounds) world with | Some property when property.PropertyType = typeof -> entity.ResetProbeBounds world | Some _ | None -> () - let private createEntity atMouse inHierarchy world = + let private createEntity atMouse inHierarchy dispatcherNameOverride parentOverride world = snapshot CreateEntity world - let dispatcherName = NewEntityDispatcherName + let dispatcherName = Option.defaultValue NewEntityDispatcherName dispatcherNameOverride let overlayNameDescriptor = match NewEntityOverlayName with | "(Default Overlay)" -> DefaultOverlay @@ -902,7 +903,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= then Array.add name entity.Surnames else [|name|] else - match NewEntityParentOpt with + match Option.orElse NewEntityParentOpt parentOverride with | Some newEntityParent when newEntityParent.GetExists world -> Array.add name newEntityParent.Surnames | Some _ | None -> [|name|] | None -> [|name|] @@ -911,6 +912,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= selectEntityOpt (Some entity) world ImGui.SetWindowFocus "Viewport" ShowSelectedEntity <- true + entity let private trySaveSelectedEntity filePath world = match SelectedEntityOpt with @@ -1021,7 +1023,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= true | Some _ | None -> false - let rec private propagateEntityStructure entity world = + let private propagateEntityStructure entity world = snapshot PropagateEntity world World.propagateEntityStructure entity world @@ -1453,6 +1455,68 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= (* Update Functions *) + let private updateEyeDrag world = + if canEditWithMouse world then + if ImGui.IsMouseClicked ImGuiMouseButton.Middle then + let mousePositionInset = World.getMousePosition2dInset world + let dragState = DragEye2dCenter (world.Eye2dCenter + mousePositionInset, mousePositionInset) + DragEyeState <- dragState + match DragEyeState with + | DragEye2dCenter (entityDragOffset, mousePositionInsetOrig) -> + let mousePositionInset = World.getMousePosition2dInset world + DesiredEye2dCenter <- (entityDragOffset - mousePositionInsetOrig) + -Constants.Gaia.EyeSpeed * (mousePositionInset - mousePositionInsetOrig) + DragEyeState <- DragEye2dCenter (entityDragOffset, mousePositionInsetOrig) + | DragEyeInactive -> () + if ImGui.IsMouseReleased ImGuiMouseButton.Middle then + match DragEyeState with + | DragEye2dCenter _ -> DragEyeState <- DragEyeInactive + | DragEyeInactive -> () + + let private updateEyeTravel world = + if canEditWithKeyboard world then + let delta = world.DateDelta + let seconds = single delta.TotalSeconds + let center = world.Eye3dCenter + let rotation = world.Eye3dRotation + let moveSpeed = + if ImGui.IsEnterDown () && ImGui.IsShiftDown () then 512.0f * seconds + elif ImGui.IsEnterDown () then 64.0f * seconds + elif ImGui.IsShiftDown () then 1.0f * seconds + else 8.0f * seconds + let turnSpeed = + if ImGui.IsShiftDown () && ImGui.IsEnterUp () then 1.5f * seconds + else 3.0f * seconds + if ImGui.IsKeyDown ImGuiKey.W && ImGui.IsCtrlUp () && ImGui.IsAltUp () then + DesiredEye3dCenter <- center + v3Forward.Transform rotation * moveSpeed + if ImGui.IsKeyDown ImGuiKey.S && ImGui.IsCtrlUp () && ImGui.IsAltUp () then + DesiredEye3dCenter <- center + v3Back.Transform rotation * moveSpeed + if ImGui.IsKeyDown ImGuiKey.A && ImGui.IsCtrlUp () && ImGui.IsAltUp () then + DesiredEye3dCenter <- center + v3Left.Transform rotation * moveSpeed + if ImGui.IsKeyDown ImGuiKey.D && ImGui.IsCtrlUp () && ImGui.IsAltUp () then + DesiredEye3dCenter <- center + v3Right.Transform rotation * moveSpeed + if ImGui.IsKeyDown (if AlternativeEyeTravelInput then ImGuiKey.UpArrow else ImGuiKey.E) && ImGui.IsCtrlUp () then + let rotation' = rotation * Quaternion.CreateFromAxisAngle (v3Right, turnSpeed) + DesiredEye3dRotation <- + if rotation'.Forward.Dot v3Up < 0.99f then rotation' + else + Quaternion.CreateFromAxisAngle (v3Down, 2.0f * MathF.Atan2(rotation.Z, rotation.W)) * + Quaternion.CreateFromAxisAngle (v3Right, MathF.PI_OVER_2) + if ImGui.IsKeyDown (if AlternativeEyeTravelInput then ImGuiKey.DownArrow else ImGuiKey.Q) && ImGui.IsCtrlUp () then + let rotation' = rotation * Quaternion.CreateFromAxisAngle (v3Left, turnSpeed) + DesiredEye3dRotation <- + if rotation'.Forward.Dot v3Down < 0.99f then rotation' + else + Quaternion.CreateFromAxisAngle (v3Up, 2.0f * MathF.Atan2(rotation.Z, rotation.W)) * + Quaternion.CreateFromAxisAngle (v3Right, -MathF.PI_OVER_2) + if ImGui.IsKeyDown (if AlternativeEyeTravelInput then ImGuiKey.E else ImGuiKey.UpArrow) && ImGui.IsAltUp () then + DesiredEye3dCenter <- center + v3Up.Transform rotation * moveSpeed + if ImGui.IsKeyDown (if AlternativeEyeTravelInput then ImGuiKey.Q else ImGuiKey.DownArrow) && ImGui.IsAltUp () then + DesiredEye3dCenter <- center + v3Down.Transform rotation * moveSpeed + if ImGui.IsKeyDown ImGuiKey.LeftArrow && ImGui.IsAltUp () then + DesiredEye3dRotation <- Quaternion.CreateFromAxisAngle (v3Up, turnSpeed) * rotation + if ImGui.IsKeyDown ImGuiKey.RightArrow && ImGui.IsAltUp () then + DesiredEye3dRotation <- Quaternion.CreateFromAxisAngle (v3Down, turnSpeed) * rotation + let private updateEntityContext world = if canEditWithMouse world then if ImGui.IsMouseReleased ImGuiMouseButton.Right then @@ -1569,67 +1633,48 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= | DragEntityPosition2d _ | DragEntityRotation2d _ -> DragEntityState <- DragEntityInactive | DragEntityInactive -> () - let private updateEyeDrag world = - if canEditWithMouse world then - if ImGui.IsMouseClicked ImGuiMouseButton.Middle then - let mousePositionInset = World.getMousePosition2dInset world - let dragState = DragEye2dCenter (world.Eye2dCenter + mousePositionInset, mousePositionInset) - DragEyeState <- dragState - match DragEyeState with - | DragEye2dCenter (entityDragOffset, mousePositionInsetOrig) -> - let mousePositionInset = World.getMousePosition2dInset world - DesiredEye2dCenter <- (entityDragOffset - mousePositionInsetOrig) + -Constants.Gaia.EyeSpeed * (mousePositionInset - mousePositionInsetOrig) - DragEyeState <- DragEye2dCenter (entityDragOffset, mousePositionInsetOrig) - | DragEyeInactive -> () - if ImGui.IsMouseReleased ImGuiMouseButton.Middle then - match DragEyeState with - | DragEye2dCenter _ -> DragEyeState <- DragEyeInactive - | DragEyeInactive -> () - - let private updateEyeTravel world = - if canEditWithKeyboard world then - let delta = world.DateDelta - let seconds = single delta.TotalSeconds - let center = world.Eye3dCenter - let rotation = world.Eye3dRotation - let moveSpeed = - if ImGui.IsEnterDown () && ImGui.IsShiftDown () then 512.0f * seconds - elif ImGui.IsEnterDown () then 64.0f * seconds - elif ImGui.IsShiftDown () then 1.0f * seconds - else 8.0f * seconds - let turnSpeed = - if ImGui.IsShiftDown () && ImGui.IsEnterUp () then 1.5f * seconds - else 3.0f * seconds - if ImGui.IsKeyDown ImGuiKey.W && ImGui.IsCtrlUp () && ImGui.IsAltUp () then - DesiredEye3dCenter <- center + v3Forward.Transform rotation * moveSpeed - if ImGui.IsKeyDown ImGuiKey.S && ImGui.IsCtrlUp () && ImGui.IsAltUp () then - DesiredEye3dCenter <- center + v3Back.Transform rotation * moveSpeed - if ImGui.IsKeyDown ImGuiKey.A && ImGui.IsCtrlUp () && ImGui.IsAltUp () then - DesiredEye3dCenter <- center + v3Left.Transform rotation * moveSpeed - if ImGui.IsKeyDown ImGuiKey.D && ImGui.IsCtrlUp () && ImGui.IsAltUp () then - DesiredEye3dCenter <- center + v3Right.Transform rotation * moveSpeed - if ImGui.IsKeyDown (if AlternativeEyeTravelInput then ImGuiKey.UpArrow else ImGuiKey.E) && ImGui.IsCtrlUp () then - let rotation' = rotation * Quaternion.CreateFromAxisAngle (v3Right, turnSpeed) - DesiredEye3dRotation <- - if rotation'.Forward.Dot v3Up < 0.99f then rotation' - else - Quaternion.CreateFromAxisAngle (v3Down, 2.0f * MathF.Atan2(rotation.Z, rotation.W)) * - Quaternion.CreateFromAxisAngle (v3Right, MathF.PI_OVER_2) - if ImGui.IsKeyDown (if AlternativeEyeTravelInput then ImGuiKey.DownArrow else ImGuiKey.Q) && ImGui.IsCtrlUp () then - let rotation' = rotation * Quaternion.CreateFromAxisAngle (v3Left, turnSpeed) - DesiredEye3dRotation <- - if rotation'.Forward.Dot v3Down < 0.99f then rotation' - else - Quaternion.CreateFromAxisAngle (v3Up, 2.0f * MathF.Atan2(rotation.Z, rotation.W)) * - Quaternion.CreateFromAxisAngle (v3Right, -MathF.PI_OVER_2) - if ImGui.IsKeyDown (if AlternativeEyeTravelInput then ImGuiKey.E else ImGuiKey.UpArrow) && ImGui.IsAltUp () then - DesiredEye3dCenter <- center + v3Up.Transform rotation * moveSpeed - if ImGui.IsKeyDown (if AlternativeEyeTravelInput then ImGuiKey.Q else ImGuiKey.DownArrow) && ImGui.IsAltUp () then - DesiredEye3dCenter <- center + v3Down.Transform rotation * moveSpeed - if ImGui.IsKeyDown ImGuiKey.LeftArrow && ImGui.IsAltUp () then - DesiredEye3dRotation <- Quaternion.CreateFromAxisAngle (v3Up, turnSpeed) * rotation - if ImGui.IsKeyDown ImGuiKey.RightArrow && ImGui.IsAltUp () then - DesiredEye3dRotation <- Quaternion.CreateFromAxisAngle (v3Down, turnSpeed) * rotation + let private updateAssetDrag world = + let io = ImGui.GetIO () + if (*ImGui.BeginDragDropViewport ()*)true then + match DragDropPayloadOpt with + | Some (DragDropAsset (_, assetTag)) when + ImGui.IsMouseReleased ImGuiMouseButton.Left && + not io.WantCaptureMouse && + (*not (NativePtr.isNullPtr (ImGui.AcceptDragDropPayload "Asset").NativePtr)*)true -> + match Metadata.tryGetMetadata assetTag with + | ValueSome metadata -> + match metadata with + | RawMetadata -> () + | TextureMetadata _ -> + RightClickPosition <- World.getMousePosition world + let entity = createEntity true false (Some (nameof StaticSpriteDispatcher)) None world + entity.SetStaticImage (AssetTag.specialize assetTag) world + entity.AutoBounds world + | TileMapMetadata _ -> + RightClickPosition <- World.getMousePosition world + let entity = createEntity true false (Some (nameof TileMapDispatcher)) None world + entity.SetTileMap (AssetTag.specialize assetTag) world + entity.AutoBounds world + | SpineSkeletonMetadata _ -> + RightClickPosition <- World.getMousePosition world + let entity = createEntity true false (Some (nameof SpineSkeletonDispatcher)) None world + entity.SetSpineSkeleton (AssetTag.specialize assetTag) world + entity.AutoBounds world + | StaticModelMetadata _ -> + RightClickPosition <- World.getMousePosition world + let entity = createEntity true false (Some (nameof StaticModelDispatcher)) None world + entity.SetStaticModel (AssetTag.specialize assetTag) world + entity.AutoBounds world + | AnimatedModelMetadata _ -> + RightClickPosition <- World.getMousePosition world + let entity = createEntity true false (Some (nameof AnimatedModelDispatcher)) None world + entity.SetAnimatedModel (AssetTag.specialize assetTag) world + entity.AutoBounds world + | SoundMetadata -> () + | SongMetadata -> () + | ValueNone -> () + | Some _ | None -> () + (*ImGui.EndDragDropTarget ()*) let private updateHotkeys entityHierarchyFocused world = if not (modal ()) then @@ -1673,7 +1718,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= elif ImGui.IsKeyPressed ImGuiKey.X && ImGui.IsCtrlDown () then tryCutSelectedEntity world |> ignore elif ImGui.IsKeyPressed ImGuiKey.C && ImGui.IsCtrlDown () then tryCopySelectedEntity world |> ignore elif ImGui.IsKeyPressed ImGuiKey.V && ImGui.IsCtrlDown () then tryPaste PasteAtLook (Option.map cast NewEntityParentOpt) world |> ignore - elif ImGui.IsKeyPressed ImGuiKey.Enter && ImGui.IsCtrlDown () then createEntity false false world + elif ImGui.IsKeyPressed ImGuiKey.Enter && ImGui.IsCtrlDown () then createEntity false false None None world |> ignore elif ImGui.IsKeyPressed ImGuiKey.Delete then tryDeleteSelectedEntity world |> ignore elif ImGui.IsKeyPressed ImGuiKey.Escape then if not (String.IsNullOrWhiteSpace PropagationSourcesSearchStr) then @@ -1681,6 +1726,8 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= elif not (String.IsNullOrWhiteSpace EntityHierarchySearchStr) then EntityHierarchySearchStr <- "" else + ImGuiInternal.tryCancelDragDrop () + DragDropPayloadOpt <- None // TODO: P0: remove this line when AcceptDragDropPayload is exposed. focusPropertyOpt None world selectEntityOpt None world @@ -1725,9 +1772,9 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= if ImGui.BeginPopupContextItem popupContextItemTitle then if ImGui.IsMouseReleased ImGuiMouseButton.Right then openPopupContextItemWhenUnselected <- true selectEntityOpt (Some entity) world - if ImGui.MenuItem "Create Entity" then createEntity false true world + if ImGui.MenuItem "Create Entity" then createEntity false true None None world |> ignore if SelectedEntityOpt.IsSome && ImGui.MenuItem "Create Entity at Local Origin" then - createEntity true true world + createEntity true true None None world |> ignore tryMoveSelectedEntityToOrigin true world |> ignore if ImGui.MenuItem "Delete Entity" then tryDeleteSelectedEntity world |> ignore ImGui.Separator () @@ -1782,9 +1829,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= if ImGui.BeginDragDropTarget () then if not (NativePtr.isNullPtr (ImGui.AcceptDragDropPayload "Entity").NativePtr) then match DragDropPayloadOpt with - | Some payload -> - let sourceEntityAddressStr = payload - let sourceEntity = Nu.Entity sourceEntityAddressStr + | Some (DragDropEntity sourceEntity) -> if not (sourceEntity.GetProtected world) then if ImGui.IsCtrlDown () then let entityDescriptor = World.writeEntity false false EntityDescriptor.empty sourceEntity world @@ -1849,47 +1894,47 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= ShowSelectedEntity <- true else Log.warn "Cannot mount an entity circularly." else MessageBoxOpt <- Some "Cannot relocate a protected simulant (such as an entity created by the ImSim or MMCC API)." - | None -> () + | Some _ | None -> () ImGui.EndDragDropTarget () if ImGui.BeginDragDropSource () then - let entityAddressStr = entity.EntityAddress |> scstringMemo |> Symbol.distill - DragDropPayloadOpt <- Some entityAddressStr + DragDropPayloadOpt <- Some (DragDropEntity entity) ImGui.Text (entity.Name + if ImGui.IsCtrlDown () then " (Copy)" else "") ImGui.SetDragDropPayload ("Entity", IntPtr.Zero, 0u) |> ignore ImGui.EndDragDropSource () - if entity.GetExists world && entity.Has world then // check for existence since entity may have been deleted just above - let frozen = entity.GetFrozen world - let (text, color) = if frozen then ("Thaw", Color.CornflowerBlue) else ("Freeze", Color.DarkRed) - ImGui.SameLine () - ImGui.PushStyleColor (ImGuiCol.Button, color.Abgr) - ImGui.PushID ("##frozen" + scstringMemo entity) - if ImGui.SmallButton text then - let frozen = not frozen - snapshot (SetEntityFrozen frozen) world - entity.SetFrozen frozen world - ImGui.PopID () - ImGui.PopStyleColor () - let hasPropagationTargets = entity.HasPropagationTargets world - let hasPropagationDescriptorOpt = Option.isSome (entity.GetPropagatedDescriptorOpt world) - if hasPropagationTargets || hasPropagationDescriptorOpt then - ImGui.SameLine () - ImGui.PushID ("##push" + scstringMemo entity) - if ImGui.SmallButton "Push" then - propagateEntityStructure entity world - ImGui.PopID () - if ImGui.IsItemHovered ImGuiHoveredFlags.DelayNormal && ImGui.BeginTooltip () then - ImGui.Text "Propagate entity structure to all targets, preserving propagation data." - ImGui.EndTooltip () - ImGui.SameLine () - ImGui.PushID ("##wipe" + scstringMemo entity) - if ImGui.SmallButton "Wipe" then - snapshot WipePropagationTargets world - World.clearPropagationTargets entity world - entity.SetPropagatedDescriptorOpt None world - ImGui.PopID () - if ImGui.IsItemHovered ImGuiHoveredFlags.DelayNormal && ImGui.BeginTooltip () then - ImGui.Text "Clear entity structure propagation targets, wiping any propagated descriptor data." - ImGui.EndTooltip () + if entity.GetExists world then // check for existence since entity may have been deleted just above + if entity.Has world then + let frozen = entity.GetFrozen world + let (text, color) = if frozen then ("Thaw", Color.CornflowerBlue) else ("Freeze", Color.DarkRed) + ImGui.SameLine () + ImGui.PushStyleColor (ImGuiCol.Button, color.Abgr) + ImGui.PushID ("##frozen" + scstringMemo entity) + if ImGui.SmallButton text then + let frozen = not frozen + snapshot (SetEntityFrozen frozen) world + entity.SetFrozen frozen world + ImGui.PopID () + ImGui.PopStyleColor () + let hasPropagationTargets = entity.HasPropagationTargets world + let hasPropagationDescriptorOpt = Option.isSome (entity.GetPropagatedDescriptorOpt world) + if hasPropagationTargets || hasPropagationDescriptorOpt then + ImGui.SameLine () + ImGui.PushID ("##push" + scstringMemo entity) + if ImGui.SmallButton "Push" then + propagateEntityStructure entity world + ImGui.PopID () + if ImGui.IsItemHovered ImGuiHoveredFlags.DelayNormal && ImGui.BeginTooltip () then + ImGui.Text "Propagate entity structure to all targets, preserving propagation data." + ImGui.EndTooltip () + ImGui.SameLine () + ImGui.PushID ("##wipe" + scstringMemo entity) + if ImGui.SmallButton "Wipe" then + snapshot WipePropagationTargets world + World.clearPropagationTargets entity world + entity.SetPropagatedDescriptorOpt None world + ImGui.PopID () + if ImGui.IsItemHovered ImGuiHoveredFlags.DelayNormal && ImGui.BeginTooltip () then + ImGui.Text "Clear entity structure propagation targets, wiping any propagated descriptor data." + ImGui.EndTooltip () expanded let rec private imGuiEntityHierarchy (entity : Entity) world = @@ -1943,7 +1988,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= let dispatcherNames = (World.getEntityDispatchers world).Keys let dispatcherNamePicked = tryPickName dispatcherNames for dispatcherName in dispatcherNames do - if ImGui.Selectable (dispatcherName, strEq dispatcherName dispatcherNameCurrent) then + if ImGui.Selectable (dispatcherName, (dispatcherName = dispatcherNameCurrent)) then if not (entity.GetProtected world) then snapshot ChangeEntityDispatcher world World.changeEntityDispatcher dispatcherName entity world @@ -1964,7 +2009,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= if ImGui.BeginCombo ("Facet Name " + string i, facetName, ImGuiComboFlags.HeightRegular) then let facetNameSelectablePicked = tryPickName facetNamesSelectable for facetNameSelectable in facetNamesSelectable do - if ImGui.Selectable (facetNameSelectable, strEq facetName NewEntityDispatcherName) then + if ImGui.Selectable (facetNameSelectable, (facetName = NewEntityDispatcherName)) then facetName <- facetNameSelectable edited <- true if Some facetNameSelectable = facetNameSelectablePicked then ImGui.SetScrollHereY Constants.Gaia.HeightRegularPickOffset @@ -2458,7 +2503,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= // entity menu if ImGui.BeginMenu "Entity" then - if ImGui.MenuItem ("Create Entity", "Ctrl+Enter") then createEntity false false world + if ImGui.MenuItem ("Create Entity", "Ctrl+Enter") then createEntity false false None None world |> ignore if ImGui.MenuItem ("Delete Entity", "Delete") then tryDeleteSelectedEntity world |> ignore ImGui.Separator () if ImGui.MenuItem ("Cut Entity", "Ctrl+X") then tryCutSelectedEntity world |> ignore @@ -2493,14 +2538,14 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= ImGui.EndMenuBar () // tool bar - if ImGui.Button "Create" then createEntity false false world + if ImGui.Button "Create" then createEntity false false None None world |> ignore ImGui.SameLine () ImGui.SetNextItemWidth 200.0f if ImGui.BeginCombo ("##newEntityDispatcherName", NewEntityDispatcherName, ImGuiComboFlags.HeightRegular) then let dispatcherNames = (World.getEntityDispatchers world).Keys let dispatcherNamePicked = tryPickName dispatcherNames for dispatcherName in dispatcherNames do - if ImGui.Selectable (dispatcherName, strEq dispatcherName NewEntityDispatcherName) then NewEntityDispatcherName <- dispatcherName + if ImGui.Selectable (dispatcherName, (dispatcherName = NewEntityDispatcherName)) then NewEntityDispatcherName <- dispatcherName if Some dispatcherName = dispatcherNamePicked then ImGui.SetScrollHereY Constants.Gaia.HeightRegularPickOffset if dispatcherName = NewEntityDispatcherName then ImGui.SetItemDefaultFocus () ImGui.EndCombo () @@ -2512,7 +2557,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= if ImGui.BeginCombo ("##newEntityOverlayName", NewEntityOverlayName, ImGuiComboFlags.HeightRegular) then let overlayNamePicked = tryPickName overlayNames for overlayName in overlayNames do - if ImGui.Selectable (overlayName, strEq overlayName NewEntityOverlayName) then NewEntityOverlayName <- overlayName + if ImGui.Selectable (overlayName, (overlayName = NewEntityOverlayName)) then NewEntityOverlayName <- overlayName if Some overlayName = overlayNamePicked then ImGui.SetScrollHereY Constants.Gaia.HeightRegularPickOffset if overlayName = NewEntityOverlayName then ImGui.SetItemDefaultFocus () ImGui.EndCombo () @@ -2567,7 +2612,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= if ImGui.BeginCombo ("##projectEditMode", ProjectEditMode, ImGuiComboFlags.HeightRegular) then let editModes = World.getEditModes world for (editModeName, editModeFn) in editModes.Pairs do - if ImGui.Selectable (editModeName, strEq editModeName ProjectEditMode) then + if ImGui.Selectable (editModeName, (editModeName = ProjectEditMode)) then ProjectEditMode <- editModeName snapshot (SetEditMode 0) world // snapshot before mode change selectEntityOpt None world @@ -2681,7 +2726,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= ImGui.SetNextItemWidth -1.0f if ImGui.BeginCombo ("##selectedGroupName", selectedGroupName, ImGuiComboFlags.HeightRegular) then for group in groups do - if ImGui.Selectable (group.Name, strEq group.Name selectedGroupName) then + if ImGui.Selectable (group.Name, group.Name = selectedGroupName) then selectEntityOpt None world selectGroup true group if group.Name = selectedGroupName then ImGui.SetItemDefaultFocus () @@ -2689,9 +2734,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= if ImGui.BeginDragDropTarget () then if not (NativePtr.isNullPtr (ImGui.AcceptDragDropPayload "Entity").NativePtr) then match DragDropPayloadOpt with - | Some payload -> - let sourceEntityAddressStr = payload - let sourceEntity = Nu.Entity sourceEntityAddressStr + | Some (DragDropEntity sourceEntity) -> if not (sourceEntity.GetProtected world) then if ImGui.IsCtrlDown () then let entityDescriptor = World.writeEntity false false EntityDescriptor.empty sourceEntity world @@ -2718,14 +2761,14 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= let sourceEntity' = Nu.Entity (SelectedGroup.GroupAddress <-- Address.makeFromName sourceEntity.Name) if not (sourceEntity'.GetExists world) then if World.getEntityAllowedToMount sourceEntity world then - sourceEntity.SetMountOptWithAdjustment None world + sourceEntity.SetMountOptWithAdjustment false None world World.renameEntityImmediate sourceEntity sourceEntity' world if NewEntityParentOpt = Some sourceEntity then NewEntityParentOpt <- Some sourceEntity' selectEntityOpt (Some sourceEntity') world ShowSelectedEntity <- true else MessageBoxOpt <- Some "Cannot unparent an entity when there exists another unparented entity with the same name." else MessageBoxOpt <- Some "Cannot relocate a protected simulant (such as an entity created by the ImSim or MMCC API)." - | None -> () + | Some _ | None -> () ImGui.EndDragDropTarget () // entity editing @@ -2862,13 +2905,8 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= ImGui.PushID ("##asChild" + scstringMemo entity) if ImGui.SmallButton "as Child" then snapshot DuplicateEntity world - let parent = - SelectedEntityOpt - |> Option.map cast - |> Option.orElse (Option.map cast NewEntityParentOpt) - |> Option.defaultValue entity.Group let positionSnapEir = if Snaps2dSelected then Left (a__ Snaps2d) else Right (a__ Snaps3d) - let duplicate = World.pasteEntity NewEntityDistance RightClickPosition positionSnapEir PasteAtLook entity parent world + let duplicate = World.pasteEntity NewEntityDistance RightClickPosition positionSnapEir PasteAtLook entity selectedEntity world selectEntityOpt (Some duplicate) world ImGui.PopID () if ImGui.IsItemHovered ImGuiHoveredFlags.DelayNormal && ImGui.BeginTooltip () then @@ -2878,13 +2916,8 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= ImGui.PushID ("##atLocalOrigin" + scstringMemo entity) if ImGui.SmallButton "at Local Origin" then snapshot DuplicateEntity world - let parent = - SelectedEntityOpt - |> Option.map cast - |> Option.orElse (Option.map cast NewEntityParentOpt) - |> Option.defaultValue entity.Group let positionSnapEir = if Snaps2dSelected then Left (a__ Snaps2d) else Right (a__ Snaps3d) - let duplicate = World.pasteEntity NewEntityDistance RightClickPosition positionSnapEir PasteAtLook entity parent world + let duplicate = World.pasteEntity NewEntityDistance RightClickPosition positionSnapEir PasteAtLook entity selectedEntity world duplicate.SetPositionLocal v3Zero world selectEntityOpt (Some duplicate) world ImGui.PopID () @@ -2990,15 +3023,15 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= if isPropertyAssetTag && ImGui.BeginDragDropTarget () then if not (NativePtr.isNullPtr (ImGui.AcceptDragDropPayload "Asset").NativePtr) then match DragDropPayloadOpt with - | Some payload -> + | Some (DragDropAsset (assetTagStr, _)) -> let pasts = Pasts - try let propertyValueEscaped = payload + try let propertyValueEscaped = assetTagStr let propertyValueUnescaped = String.unescape propertyValueEscaped let propertyValue = converter.ConvertFromString propertyValueUnescaped setPropertyValue false propertyValue propertyDescriptor simulant world with _ -> Pasts <- pasts - | None -> () + | Some _ | None -> () ImGui.EndDragDropTarget () with :? TargetException as exn -> PropertyFocusedOpt <- None @@ -3208,7 +3241,8 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= ImGui.Text "Clear evaluation output (Alt+C)" ImGui.EndTooltip () if InteractiveInputFocusRequested then ImGui.SetKeyboardFocusHere (); InteractiveInputFocusRequested <- false - ImGui.InputTextMultiline ("##interactiveInputStr", &InteractiveInputStr, 131072u, v2 -1.0f 130.0f, if eval then ImGuiInputTextFlags.ReadOnly else ImGuiInputTextFlags.None) |> ignore + let inputTextHeight = ImGui.GetContentRegionAvail().Y * 0.65f + ImGui.InputTextMultiline ("##interactiveInputStr", &InteractiveInputStr, 131072u, v2 -1.0f inputTextHeight, if eval then ImGuiInputTextFlags.ReadOnly else ImGuiInputTextFlags.None) |> ignore if enter then InteractiveInputStr <- "" if eval || enter then InteractiveInputFocusRequested <- true ImGui.Separator () @@ -3337,7 +3371,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= | 0 -> Snaps2dSelected <- true | _ -> Snaps2dSelected <- false if ImGui.IsItemHovered ImGuiHoveredFlags.DelayNormal && ImGui.BeginTooltip () then - ImGui.Text "Use 2d or 3d snapping (F3 to swap mode)." + ImGui.Text "Use 2d or 3d snapping (F3 to switch)." ImGui.EndTooltip () ImGui.SameLine () let mutable (p, d, s) = if Snaps2dSelected then Snaps2d else Snaps3d @@ -3374,26 +3408,44 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= let windowName = "Asset Viewer" if ImGui.Begin (windowName, ImGuiWindowFlags.NoNav) then if ImGui.IsWindowFocused () && SelectedWindowRestoreRequested = 0 then SelectedWindowOpt <- Some windowName - ImGui.SetNextItemWidth -1.0f + ImGui.SetNextItemWidth (ImGui.GetContentRegionAvail().X * 0.5f) let searchActivePrevious = not (String.IsNullOrWhiteSpace AssetViewerSearchStr) if AssetViewerSearchRequested then ImGui.SetKeyboardFocusHere () AssetViewerSearchStr <- "" AssetViewerSearchRequested <- false - ImGui.InputTextWithHint ("##assetViewerSearchStr", "[enter search text]", &AssetViewerSearchStr, 4096u) |> ignore + ImGui.InputTextWithHint ("##assetViewerSearchStr", "[search text]", &AssetViewerSearchStr, 4096u) |> ignore let searchActiveCurrent = not (String.IsNullOrWhiteSpace AssetViewerSearchStr) let searchDeactivated = searchActivePrevious && not searchActiveCurrent + ImGui.SameLine () + ImGui.SetNextItemWidth -1.0f + if ImGui.InputTextWithHint ("##loadPackageName", "[package to load]", &LoadPackageName, 4096u, ImGuiInputTextFlags.EnterReturnsTrue) then + Metadata.loadMetadataPackage LoadPackageName + LoadPackageName <- "" ImGui.BeginChild "Container" |> ignore for packageEntry in Metadata.getMetadataPackagesLoaded () |> Array.sortWith (fun a b -> String.Compare (a.Key, b.Key, true)) do - let flags = ImGuiTreeNodeFlags.SpanAvailWidth ||| ImGuiTreeNodeFlags.OpenOnArrow + let flags = ImGuiTreeNodeFlags.OpenOnArrow if searchActiveCurrent then ImGui.SetNextItemOpen true if searchDeactivated then ImGui.SetNextItemOpen false if ImGui.TreeNodeEx (packageEntry.Key, flags) then for assetEntry in packageEntry.Value |> Array.sortWith (fun a b -> String.Compare (a.Key, b.Key, true)) do + let packageName = packageEntry.Key let assetName = assetEntry.Key - if (assetName.ToLowerInvariant ()).Contains (AssetViewerSearchStr.ToLowerInvariant ()) then + let retained = assetName.ToLowerInvariant().Contains(AssetViewerSearchStr.ToLowerInvariant ()) + let nonIcon = not (Assets.Default.Icons.Contains (asset packageName assetName)) + if retained && nonIcon then let assetImageSize = v2Dup (ImGui.GetFontSize () + 3.0f) - match World.imGuiTryGetTextureId (asset packageEntry.Key assetName) world with + let image = + match __c assetEntry.Value with + | RawMetadata -> Assets.Default.RawIconIcon + | TextureMetadata _ -> asset packageName assetName + | TileMapMetadata _ -> Assets.Default.TileMapIcon + | SpineSkeletonMetadata _ -> Assets.Default.SpineSkeletonIcon + | StaticModelMetadata _ -> Assets.Default.StaticModelIcon + | AnimatedModelMetadata _ -> Assets.Default.AnimatedModelIcon + | SoundMetadata -> Assets.Default.SoundIcon + | SongMetadata -> Assets.Default.SongIcon + match World.imGuiTryGetTextureId image world with | ValueSome textureId -> ImGui.Image (nativeint textureId, assetImageSize) if ImGui.IsItemHovered ImGuiHoveredFlags.DelayShort then @@ -3409,13 +3461,68 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= ImGui.SameLine () ImGui.TreeNodeEx (assetName, flags ||| ImGuiTreeNodeFlags.Leaf) |> ignore if ImGui.BeginDragDropSource () then // NOTE: it appears that drag-dropping only works from nodes in Dear ImGui. - let packageNameText = if Symbol.shouldBeExplicit packageEntry.Key then String.surround "\"" packageEntry.Key else packageEntry.Key + let packageNameText = if Symbol.shouldBeExplicit packageName then String.surround "\"" packageName else packageName let assetNameText = if Symbol.shouldBeExplicit assetName then String.surround "\"" assetName else assetName let assetTagStr = "[" + packageNameText + " " + assetNameText + "]" - DragDropPayloadOpt <- Some assetTagStr + DragDropPayloadOpt <- Some (DragDropAsset (assetTagStr, asset packageName assetName)) ImGui.Text assetTagStr ImGui.SetDragDropPayload ("Asset", IntPtr.Zero, 0u) |> ignore ImGui.EndDragDropSource () + let creatorOpt = + match __c assetEntry.Value with + | RawMetadata -> None + | TextureMetadata _ -> + (fun parentOpt world -> + let entity = createEntity false false (Some (nameof StaticSpriteDispatcher)) parentOpt world + entity.SetStaticImage (asset packageName assetName) world + entity.AutoBounds world + entity) |> Some + | TileMapMetadata _ -> + (fun parentOpt world -> + let entity = createEntity false false (Some (nameof TileMapDispatcher)) parentOpt world + entity.SetTileMap (asset packageName assetName) world + entity.AutoBounds world + entity) |> Some + | SpineSkeletonMetadata _ -> + (fun parentOpt world -> + let entity = createEntity false false (Some (nameof SpineSkeletonDispatcher)) parentOpt world + entity.SetSpineSkeleton (asset packageName assetName) world + entity.AutoBounds world + entity) |> Some + | StaticModelMetadata _ -> + (fun parentOpt world -> + let entity = createEntity false false (Some (nameof StaticModelDispatcher)) parentOpt world + entity.SetStaticModel (asset packageName assetName) world + entity.AutoBounds world + entity) |> Some + | AnimatedModelMetadata _ -> + (fun parentOpt world -> + let entity = createEntity false false (Some (nameof AnimatedModelDispatcher)) parentOpt world + entity.SetAnimatedModel (asset packageName assetName) world + entity.AutoBounds world + entity) |> Some + | SoundMetadata -> + ImGui.SameLine () + if ImGui.SmallButton "Play" then + World.playSound 0.0f 0.0f 1.0f (asset packageName assetName) world + None + | SongMetadata -> None + match creatorOpt with + | Some creator -> + ImGui.SameLine () + if ImGui.SmallButton "Create" then + creator None world |> ignore + match SelectedEntityOpt with + | Some selectedEntity -> + ImGui.SameLine () + if ImGui.SmallButton "as Child" then + creator (Some selectedEntity) world |> ignore + ImGui.SameLine () + if ImGui.SmallButton "at Local Origin" then + let entity = creator (Some selectedEntity) world + entity.SetPositionLocal v3Zero world + | None -> () + | None -> () ImGui.TreePop () ImGui.TreePop () ImGui.EndChild () @@ -3642,7 +3749,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= let dispatcherNames = (World.getGroupDispatchers world).Keys let dispatcherNamePicked = tryPickName dispatcherNames for dispatcherName in dispatcherNames do - if ImGui.Selectable (dispatcherName, strEq dispatcherName NewGroupDispatcherName) then NewGroupDispatcherName <- dispatcherName + if ImGui.Selectable (dispatcherName, (dispatcherName = NewGroupDispatcherName)) then NewGroupDispatcherName <- dispatcherName if Some dispatcherName = dispatcherNamePicked then ImGui.SetScrollHereY Constants.Gaia.HeightRegularPickOffset if dispatcherName = NewGroupDispatcherName then ImGui.SetItemDefaultFocus () ImGui.EndCombo () @@ -3855,7 +3962,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= ImGui.SetNextWindowSize (v2 290.0f -1.0f) if ImGui.Begin ("Context Menu", ImGuiWindowFlags.NoTitleBar ||| ImGuiWindowFlags.NoNav) then if ImGui.Button "Create" then - createEntity true false world + createEntity true false None None world |> ignore ShowEntityContextMenu <- false ImGui.SameLine () ImGui.SetNextItemWidth -1.0f @@ -3863,18 +3970,18 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= let dispatcherNames = (World.getEntityDispatchers world).Keys let dispatcherNamePicked = tryPickName dispatcherNames for dispatcherName in dispatcherNames do - if ImGui.Selectable (dispatcherName, strEq dispatcherName NewEntityDispatcherName) then + if ImGui.Selectable (dispatcherName, (dispatcherName = NewEntityDispatcherName)) then NewEntityDispatcherName <- dispatcherName if Some dispatcherName = dispatcherNamePicked then ImGui.SetScrollHereY Constants.Gaia.HeightRegularPickOffset if dispatcherName = NewEntityDispatcherName then ImGui.SetItemDefaultFocus () ImGui.EndCombo () if SelectedEntityOpt.IsSome then if ImGui.Button "Create as Child" then - createEntity true true world + createEntity true true None None world |> ignore ShowEntityContextMenu <- false ImGui.SameLine () if ImGui.Button "at Local Origin" then - createEntity true true world + createEntity true true None None world |> ignore tryMoveSelectedEntityToOrigin true world |> ignore ShowEntityContextMenu <- false if ImGui.Button "Delete" then @@ -4103,8 +4210,15 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= updateEyeTravel world updateEntityContext world updateEntityDrag world + updateAssetDrag world updateHotkeys entityHierarchyFocused world + // HACK: because ImGui.BeginDragDropViewport isn't available yet - + // https://github.com/ocornut/imgui/issues/5204 + // we rely on the DragDropPayloadOpt value being Nonified with the following mouse input check. + // TODO: P0: get rid of this ASAP so we can rely on ImGui.AcceptDragDropPayload exclusively. + if not (ImGui.IsMouseDown ImGuiMouseButton.Left) then DragDropPayloadOpt <- None + // reloading dialogs if ReloadAssetsRequested > 0 then imGuiReloadingAssetsDialog world if ReloadCodeRequested > 0 then imGuiReloadingCodeDialog world @@ -4282,7 +4396,7 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1280,720 Split= Log.error errorMsg Constants.Engine.ExitCodeFailure - let rec private runWithCleanUp gaiaState targetDir_ screen world = + let private runWithCleanUp gaiaState targetDir_ screen world = OpenProjectFilePath <- gaiaState.ProjectDllPath OpenProjectImperativeExecution <- gaiaState.ProjectImperativeExecution CloseProjectImperativeExecution <- gaiaState.ProjectImperativeExecution diff --git a/Nu/Nu.Gaia/GaiaConstants.fs b/Nu/Nu.Gaia/GaiaConstants.fs index a30e12f831..70b027b3a2 100644 --- a/Nu/Nu.Gaia/GaiaConstants.fs +++ b/Nu/Nu.Gaia/GaiaConstants.fs @@ -12,7 +12,7 @@ module Constants = [] module Gaia = - let [] LogCharactersMax = Constants.Runtime.LohSize / sizeof - 5000 // NOTE: small enough not to allocate on the LOH. + let [] LogCharactersMax = Constants.Runtime.LohSize / sizeof - 5000 // NOTE: small enough to not allocate on the LOH. let [] PositionSnap2dDefault = 8.0f let [] DegreesSnap2dDefault = 5.0f let [] ScaleSnap2dDefault = 0.1f @@ -31,15 +31,15 @@ module Constants = let [] InteractiveInputFilePath = "input.fsx" let [] NonePick = "\"None\"" let [] EventFilter = - EventFilter.NotAny - [EventFilter.Pattern (Rexpr "PreUpdate", []) - EventFilter.Pattern (Rexpr "Update", []) - EventFilter.Pattern (Rexpr "PostUpdate", []) - EventFilter.Pattern (Rexpr "Render", []) - EventFilter.Pattern (Rexpr "Change", []) - EventFilter.Pattern (Rexpr "Integration", []) - EventFilter.Pattern (Rexpr "BodyTransform", []) - EventFilter.Pattern (Rexpr "Mouse/Move", [])] + NotAny + [Pattern (Rexpr "PreUpdate", []) + Pattern (Rexpr "Update", []) + Pattern (Rexpr "PostUpdate", []) + Pattern (Rexpr "Render", []) + Pattern (Rexpr "Change", []) + Pattern (Rexpr "Integration", []) + Pattern (Rexpr "BodyTransform", []) + Pattern (Rexpr "Mouse/Move", [])] let [] BuildName = #if DEBUG "Debug" diff --git a/Nu/Nu.Gaia/GaiaPrelude.fs b/Nu/Nu.Gaia/GaiaPrelude.fs index 065e9b48c1..11faa6f880 100644 --- a/Nu/Nu.Gaia/GaiaPrelude.fs +++ b/Nu/Nu.Gaia/GaiaPrelude.fs @@ -14,7 +14,7 @@ type DragEntityState = | DragEntityInactive type DragEyeState = - | DragEye2dCenter of Vector2 * Vector2 + | DragEye2dCenter of Offset : Vector2 * Origin : Vector2 | DragEyeInactive type [] GaiaState = diff --git a/Nu/Nu.Math/Box2.cs b/Nu/Nu.Math/Box2.cs index adca71c904..611dfbc210 100644 --- a/Nu/Nu.Math/Box2.cs +++ b/Nu/Nu.Math/Box2.cs @@ -375,5 +375,20 @@ public readonly void Intersects(in Box2 box, out bool result) min.X > max2.X || min.Y > max2.Y); } + + /// + /// Clips this to the given . + /// + /// The bounds to clip to. + /// The clipped . + public readonly Box2 Clip(Box2 bounds) + { + var min = Vector2.Max(Min, bounds.Min); + var max = Vector2.Min(Min + Size, bounds.Min + bounds.Size); + var newSize = max - min; + newSize.X = System.Math.Max(0.0f, newSize.X); + newSize.Y = System.Math.Max(0.0f, newSize.Y); + return new Box2(min, newSize); + } } } diff --git a/Nu/Nu.Math/Box2i.cs b/Nu/Nu.Math/Box2i.cs index f6621f21ba..9542553591 100644 --- a/Nu/Nu.Math/Box2i.cs +++ b/Nu/Nu.Math/Box2i.cs @@ -205,5 +205,20 @@ public override readonly string ToString() { return $"{{Min:{Min} Size:{Size}}}"; } + + /// + /// Clips this to the given . + /// + /// The bounds to clip to. + /// The clipped . + public readonly Box2i Clip(Box2i bounds) + { + var min = Vector2i.Max(Min, bounds.Min); + var max = Vector2i.Min(Min + Size, bounds.Min + bounds.Size); + var newSize = max - min; + newSize.X = System.Math.Max(0, newSize.X); + newSize.Y = System.Math.Max(0, newSize.Y); + return new Box2i(min, newSize); + } } } diff --git a/Nu/Nu.Math/Box3.cs b/Nu/Nu.Math/Box3.cs index d8c5dd1bd6..e3501f8f65 100644 --- a/Nu/Nu.Math/Box3.cs +++ b/Nu/Nu.Math/Box3.cs @@ -673,5 +673,21 @@ public readonly void Intersects(in Plane3 plane, out PlaneIntersectionType resul result = PlaneIntersectionType.Intersecting; } + + /// + /// Clips this to the given . + /// + /// The bounds to clip to. + /// The clipped . + public readonly Box3 Clip(Box3 bounds) + { + var min = Vector3.Max(Min, bounds.Min); + var max = Vector3.Min(Min + Size, bounds.Min + bounds.Size); + var newSize = max - min; + newSize.X = System.Math.Max(0.0f, newSize.X); + newSize.Y = System.Math.Max(0.0f, newSize.Y); + newSize.Z = System.Math.Max(0.0f, newSize.Z); + return new Box3(min, newSize); + } } } diff --git a/Nu/Nu.Math/Box3i.cs b/Nu/Nu.Math/Box3i.cs index 90cccac060..e70f617526 100644 --- a/Nu/Nu.Math/Box3i.cs +++ b/Nu/Nu.Math/Box3i.cs @@ -429,5 +429,21 @@ public readonly void Intersects(in Box3i box, out bool result) min.Y > max2.Y || min.Z > max2.Z); } + + /// + /// Clips this to the given . + /// + /// The bounds to clip to. + /// The clipped . + public readonly Box3i Clip(Box3i bounds) + { + var min = Vector3i.Max(Min, bounds.Min); + var max = Vector3i.Min(Min + Size, bounds.Min + bounds.Size); + var newSize = max - min; + newSize.X = System.Math.Max(0, newSize.X); + newSize.Y = System.Math.Max(0, newSize.Y); + newSize.Z = System.Math.Max(0, newSize.Z); + return new Box3i(min, newSize); + } } } diff --git a/Nu/Nu.Math/Nu.Math.csproj b/Nu/Nu.Math/Nu.Math.csproj index 7b483cce7f..3746adf475 100644 --- a/Nu/Nu.Math/Nu.Math.csproj +++ b/Nu/Nu.Math/Nu.Math.csproj @@ -21,8 +21,4 @@ 7 - - - - \ No newline at end of file diff --git a/Nu/Nu.Math/Vector2i.cs b/Nu/Nu.Math/Vector2i.cs index fd4b75ab3e..9295882924 100644 --- a/Nu/Nu.Math/Vector2i.cs +++ b/Nu/Nu.Math/Vector2i.cs @@ -277,7 +277,7 @@ public static void Divide(in Vector2i vector, in Vector2i scale, out Vector2i re /// First operand. /// Second operand. /// The component-wise minimum. - public static Vector2i ComponentMin(Vector2i a, Vector2i b) + public static Vector2i Min(Vector2i a, Vector2i b) { a.X = a.X < b.X ? a.X : b.X; a.Y = a.Y < b.Y ? a.Y : b.Y; @@ -290,7 +290,7 @@ public static Vector2i ComponentMin(Vector2i a, Vector2i b) /// First operand. /// Second operand. /// The component-wise minimum. - public static void ComponentMin(in Vector2i a, in Vector2i b, out Vector2i result) + public static void Min(in Vector2i a, in Vector2i b, out Vector2i result) { result.X = a.X < b.X ? a.X : b.X; result.Y = a.Y < b.Y ? a.Y : b.Y; @@ -302,7 +302,7 @@ public static void ComponentMin(in Vector2i a, in Vector2i b, out Vector2i resul /// First operand. /// Second operand. /// The component-wise maximum. - public static Vector2i ComponentMax(Vector2i a, Vector2i b) + public static Vector2i Max(Vector2i a, Vector2i b) { a.X = a.X > b.X ? a.X : b.X; a.Y = a.Y > b.Y ? a.Y : b.Y; @@ -315,7 +315,7 @@ public static Vector2i ComponentMax(Vector2i a, Vector2i b) /// First operand. /// Second operand. /// The component-wise maximum. - public static void ComponentMax(in Vector2i a, in Vector2i b, out Vector2i result) + public static void Max(in Vector2i a, in Vector2i b, out Vector2i result) { result.X = a.X > b.X ? a.X : b.X; result.Y = a.Y > b.Y ? a.Y : b.Y; diff --git a/Nu/Nu.Math/Vector3i.cs b/Nu/Nu.Math/Vector3i.cs index 52078ca3b0..3f01263f6a 100644 --- a/Nu/Nu.Math/Vector3i.cs +++ b/Nu/Nu.Math/Vector3i.cs @@ -278,7 +278,7 @@ public static void Divide(in Vector3i vector, in Vector3i scale, out Vector3i re /// First operand. /// Second operand. /// The component-wise minimum. - public static Vector3i ComponentMin(Vector3i a, Vector3i b) + public static Vector3i Min(Vector3i a, Vector3i b) { a.X = a.X < b.X ? a.X : b.X; a.Y = a.Y < b.Y ? a.Y : b.Y; @@ -292,7 +292,7 @@ public static Vector3i ComponentMin(Vector3i a, Vector3i b) /// First operand. /// Second operand. /// The component-wise minimum. - public static void ComponentMin(in Vector3i a, in Vector3i b, out Vector3i result) + public static void Min(in Vector3i a, in Vector3i b, out Vector3i result) { result.X = a.X < b.X ? a.X : b.X; result.Y = a.Y < b.Y ? a.Y : b.Y; @@ -305,7 +305,7 @@ public static void ComponentMin(in Vector3i a, in Vector3i b, out Vector3i resul /// First operand. /// Second operand. /// The component-wise maximum. - public static Vector3i ComponentMax(Vector3i a, Vector3i b) + public static Vector3i Max(Vector3i a, Vector3i b) { a.X = a.X > b.X ? a.X : b.X; a.Y = a.Y > b.Y ? a.Y : b.Y; @@ -319,7 +319,7 @@ public static Vector3i ComponentMax(Vector3i a, Vector3i b) /// First operand. /// Second operand. /// The component-wise maximum. - public static void ComponentMax(in Vector3i a, in Vector3i b, out Vector3i result) + public static void Max(in Vector3i a, in Vector3i b, out Vector3i result) { result.X = a.X > b.X ? a.X : b.X; result.Y = a.Y > b.Y ? a.Y : b.Y; diff --git a/Nu/Nu.Math/Vector4i.cs b/Nu/Nu.Math/Vector4i.cs index 522a6522c3..3f7c129002 100644 --- a/Nu/Nu.Math/Vector4i.cs +++ b/Nu/Nu.Math/Vector4i.cs @@ -299,7 +299,7 @@ public static void Divide(in Vector4i vector, in Vector4i scale, out Vector4i re /// First operand. /// Second operand. /// The component-wise minimum. - public static Vector4i ComponentMin(Vector4i a, Vector4i b) + public static Vector4i Min(Vector4i a, Vector4i b) { a.X = a.X < b.X ? a.X : b.X; a.Y = a.Y < b.Y ? a.Y : b.Y; @@ -314,7 +314,7 @@ public static Vector4i ComponentMin(Vector4i a, Vector4i b) /// First operand. /// Second operand. /// The component-wise minimum. - public static void ComponentMin(in Vector4i a, in Vector4i b, out Vector4i result) + public static void Min(in Vector4i a, in Vector4i b, out Vector4i result) { result.X = a.X < b.X ? a.X : b.X; result.Y = a.Y < b.Y ? a.Y : b.Y; @@ -328,7 +328,7 @@ public static void ComponentMin(in Vector4i a, in Vector4i b, out Vector4i resul /// First operand. /// Second operand. /// The component-wise maximum. - public static Vector4i ComponentMax(Vector4i a, Vector4i b) + public static Vector4i Max(Vector4i a, Vector4i b) { a.X = a.X > b.X ? a.X : b.X; a.Y = a.Y > b.Y ? a.Y : b.Y; @@ -343,7 +343,7 @@ public static Vector4i ComponentMax(Vector4i a, Vector4i b) /// First operand. /// Second operand. /// The component-wise maximum. - public static void ComponentMax(in Vector4i a, in Vector4i b, out Vector4i result) + public static void Max(in Vector4i a, in Vector4i b, out Vector4i result) { result.X = a.X > b.X ? a.X : b.X; result.Y = a.Y > b.Y ? a.Y : b.Y; diff --git a/Nu/Nu.Pipe/Assets/Default/AnimatedModelIcon.png b/Nu/Nu.Pipe/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Nu/Nu.Pipe/Assets/Default/AnimatedModelIcon.png differ diff --git a/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Nu/Nu.Pipe/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Pipe/Assets/Default/RawIcon.png b/Nu/Nu.Pipe/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Nu/Nu.Pipe/Assets/Default/RawIcon.png differ diff --git a/Nu/Nu.Pipe/Assets/Default/SongIcon.png b/Nu/Nu.Pipe/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Nu/Nu.Pipe/Assets/Default/SongIcon.png differ diff --git a/Nu/Nu.Pipe/Assets/Default/SoundIcon.png b/Nu/Nu.Pipe/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Nu/Nu.Pipe/Assets/Default/SoundIcon.png differ diff --git a/Nu/Nu.Pipe/Assets/Default/SpineSkeletonIcon.png b/Nu/Nu.Pipe/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Nu/Nu.Pipe/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Nu/Nu.Pipe/Assets/Default/StaticModelIcon.png b/Nu/Nu.Pipe/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Nu/Nu.Pipe/Assets/Default/StaticModelIcon.png differ diff --git a/Nu/Nu.Pipe/Assets/Default/TileMapIcon.png b/Nu/Nu.Pipe/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Nu/Nu.Pipe/Assets/Default/TileMapIcon.png differ diff --git a/Nu/Nu.Spine/Nu.Spine.csproj b/Nu/Nu.Spine/Nu.Spine.csproj index 2c0be899f2..bb8010075b 100644 --- a/Nu/Nu.Spine/Nu.Spine.csproj +++ b/Nu/Nu.Spine/Nu.Spine.csproj @@ -33,4 +33,4 @@ - + \ No newline at end of file diff --git a/Nu/Nu.Spine/src/PhysicsConstraint.cs b/Nu/Nu.Spine/src/PhysicsConstraint.cs index 1ab3000a9a..bac1aca65c 100644 --- a/Nu/Nu.Spine/src/PhysicsConstraint.cs +++ b/Nu/Nu.Spine/src/PhysicsConstraint.cs @@ -53,7 +53,7 @@ public class PhysicsConstraint : IUpdatable { internal bool active; readonly Skeleton skeleton; - float remaining, lastTime; + double remaining, lastTime; public PhysicsConstraint (PhysicsConstraintData data, Skeleton skeleton) { if (data == null) throw new ArgumentNullException("data", "data cannot be null."); @@ -148,7 +148,7 @@ public void Update (Physics physics) { goto case Physics.Update; // Fall through. case Physics.Update: Skeleton skeleton = this.skeleton; - float delta = Math.Max(skeleton.time - lastTime, 0); + double delta = Math.Max(skeleton.time - lastTime, 0); remaining += delta; lastTime = skeleton.time; @@ -158,34 +158,34 @@ public void Update (Physics physics) { ux = bx; uy = by; } else { - float a = remaining, i = inertia, t = data.step, f = skeleton.data.referenceScale, d = -1; - float qx = data.limit * delta, qy = qx * Math.Abs(skeleton.ScaleY); + double a = remaining, i = inertia, t = data.step, f = skeleton.data.referenceScale, d = -1; + double qx = data.limit * delta, qy = qx * Math.Abs(skeleton.ScaleY); qx *= Math.Abs(skeleton.ScaleX); if (x || y) { if (x) { - float u = (ux - bx) * i; - xOffset += u > qx ? qx : u < -qx ? -qx : u; + double u = (ux - bx) * i; + xOffset += (float)(u > qx ? qx : u < -qx ? -qx : u); ux = bx; } if (y) { - float u = (uy - by) * i; - yOffset += u > qy ? qy : u < -qy ? -qy : u; + double u = (uy - by) * i; + yOffset += (float)(u > qy ? qy : u < -qy ? -qy : u); uy = by; } if (a >= t) { - d = (float)Math.Pow(damping, 60 * t); - float m = massInverse * t, e = strength, w = wind * f, g = (Bone.yDown ? -gravity : gravity) * f; + d = Math.Pow(damping, 60 * t); + double m = massInverse * t, e = strength, w = wind * f, g = (Bone.yDown ? -gravity : gravity) * f; do { if (x) { - xVelocity += (w - xOffset * e) * m; - xOffset += xVelocity * t; - xVelocity *= d; + xVelocity += (float)((w - xOffset * e) * m); + xOffset += (float)(xVelocity * t); + xVelocity *= (float)d; } if (y) { - yVelocity -= (g + yOffset * e) * m; - yOffset += yVelocity * t; - yVelocity *= d; + yVelocity -= (float)((g + yOffset * e) * m); + yOffset += (float)(yVelocity * t); + yVelocity *= (float)d; } a -= t; } while (a >= t); @@ -194,8 +194,8 @@ public void Update (Physics physics) { if (y) bone.worldY += yOffset * mix * data.y; } if (rotateOrShearX || scaleX) { - float ca = (float)Math.Atan2(bone.c, bone.a), c, s, mr = 0; - float dx = cx - bone.worldX, dy = cy - bone.worldY; + double ca = Math.Atan2(bone.c, bone.a), c, s, mr = 0; + double dx = cx - bone.worldX, dy = cy - bone.worldY; if (dx > qx) dx = qx; else if (dx < -qx) @@ -206,40 +206,40 @@ public void Update (Physics physics) { dy = -qy; if (rotateOrShearX) { mr = (data.rotate + data.shearX) * mix; - float r = (float)Math.Atan2(dy + ty, dx + tx) - ca - rotateOffset * mr; - rotateOffset += (r - (float)Math.Ceiling(r * MathUtils.InvPI2 - 0.5f) * MathUtils.PI2) * i; + double r = Math.Atan2(dy + ty, dx + tx) - ca - rotateOffset * mr; + rotateOffset += (float)((r - Math.Ceiling(r * MathUtils.InvPI2 - 0.5f) * MathUtils.PI2) * i); r = rotateOffset * mr + ca; - c = (float)Math.Cos(r); - s = (float)Math.Sin(r); + c = Math.Cos(r); + s = Math.Sin(r); if (scaleX) { r = l * bone.WorldScaleX; - if (r > 0) scaleOffset += (dx * c + dy * s) * i / r; + if (r > 0) scaleOffset += (float)((dx * c + dy * s) * i / r); } } else { - c = (float)Math.Cos(ca); - s = (float)Math.Sin(ca); + c = Math.Cos(ca); + s = Math.Sin(ca); float r = l * bone.WorldScaleX; - if (r > 0) scaleOffset += (dx * c + dy * s) * i / r; + if (r > 0) scaleOffset += (float)((dx * c + dy * s) * i / r); } a = remaining; if (a >= t) { - if (d == -1) d = (float)Math.Pow(damping, 60 * t); - float m = massInverse * t, e = strength, w = wind, g = (Bone.yDown ? -gravity : gravity), h = l / f; + if (d == -1) d = Math.Pow(damping, 60 * t); + double m = massInverse * t, e = strength, w = wind, g = (Bone.yDown ? -gravity : gravity), h = l / f; while (true) { a -= t; if (scaleX) { - scaleVelocity += (w * c - g * s - scaleOffset * e) * m; - scaleOffset += scaleVelocity * t; - scaleVelocity *= d; + scaleVelocity += (float)((w * c - g * s - scaleOffset * e) * m); + scaleOffset += (float)(scaleVelocity * t); + scaleVelocity *= (float)d; } if (rotateOrShearX) { - rotateVelocity -= ((w * s + g * c) * h + rotateOffset * e) * m; - rotateOffset += rotateVelocity * t; - rotateVelocity *= d; + rotateVelocity -= (float)(((w * s + g * c) * h + rotateOffset * e) * m); + rotateOffset += (float)(rotateVelocity * t); + rotateVelocity *= (float)d; if (a < t) break; - float r = rotateOffset * mr + ca; - c = (float)Math.Cos(r); - s = (float)Math.Sin(r); + double r = (float)(rotateOffset * mr + ca); + c = Math.Cos(r); + s = Math.Sin(r); } else if (a < t) // break; } @@ -257,33 +257,33 @@ public void Update (Physics physics) { } if (rotateOrShearX) { - float o = rotateOffset * mix, s, c, a; + double o = rotateOffset * mix, s, c, a; if (data.shearX > 0) { - float r = 0; + double r = 0.0; if (data.rotate > 0) { r = o * data.rotate; - s = (float)Math.Sin(r); - c = (float)Math.Cos(r); + s = Math.Sin(r); + c = Math.Cos(r); a = bone.b; - bone.b = c * a - s * bone.d; - bone.d = s * a + c * bone.d; + bone.b = (float)(c * a - s * bone.d); + bone.d = (float)(s * a + c * bone.d); } r += o * data.shearX; - s = (float)Math.Sin(r); - c = (float)Math.Cos(r); + s = Math.Sin(r); + c = Math.Cos(r); a = bone.a; - bone.a = c * a - s * bone.c; - bone.c = s * a + c * bone.c; + bone.a = (float)(c * a - s * bone.c); + bone.c = (float)(s * a + c * bone.c); } else { o *= data.rotate; - s = (float)Math.Sin(o); - c = (float)Math.Cos(o); + s = Math.Sin(o); + c = Math.Cos(o); a = bone.a; - bone.a = c * a - s * bone.c; - bone.c = s * a + c * bone.c; + bone.a = (float)(c * a - s * bone.c); + bone.c = (float)(s * a + c * bone.c); a = bone.b; - bone.b = c * a - s * bone.d; - bone.d = s * a + c * bone.d; + bone.b = (float)(c * a - s * bone.d); + bone.d = (float)(s * a + c * bone.d); } } if (scaleX) { diff --git a/Nu/Nu.Spine/src/Skeleton.cs b/Nu/Nu.Spine/src/Skeleton.cs index 5f9f1e49e5..fe679cfd59 100644 --- a/Nu/Nu.Spine/src/Skeleton.cs +++ b/Nu/Nu.Spine/src/Skeleton.cs @@ -43,7 +43,8 @@ public class Skeleton { internal ExposedList updateCache = new ExposedList(); internal Skin skin; internal float r = 1, g = 1, b = 1, a = 1; - internal float x, y, scaleX = 1, time; + internal float x, y, scaleX = 1; + internal double time; /// Private to enforce usage of ScaleY getter taking Bone.yDown into account. private float scaleY = 1; @@ -103,7 +104,7 @@ public Skin Skin { public bool FlipY { get { return scaleY < 0; } set { scaleY = value ? -1f : 1f; } } /// Returns the skeleton's time. This is used for time-based manipulations, such as . /// - public float Time { get { return time; } set { time = value; } } + public double Time { get { return time; } set { time = value; } } /// Returns the root bone, or null if the skeleton has no bones. public Bone RootBone { diff --git a/Nu/Nu.Template.ImSim.Empty/Assets/Default/AnimatedModelIcon.png b/Nu/Nu.Template.ImSim.Empty/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Nu/Nu.Template.ImSim.Empty/Assets/Default/AnimatedModelIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Nu/Nu.Template.ImSim.Empty/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Template.ImSim.Empty/Assets/Default/RawIcon.png b/Nu/Nu.Template.ImSim.Empty/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Nu/Nu.Template.ImSim.Empty/Assets/Default/RawIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Empty/Assets/Default/SongIcon.png b/Nu/Nu.Template.ImSim.Empty/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Nu/Nu.Template.ImSim.Empty/Assets/Default/SongIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Empty/Assets/Default/SoundIcon.png b/Nu/Nu.Template.ImSim.Empty/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Nu/Nu.Template.ImSim.Empty/Assets/Default/SoundIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Empty/Assets/Default/SpineSkeletonIcon.png b/Nu/Nu.Template.ImSim.Empty/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Nu/Nu.Template.ImSim.Empty/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Empty/Assets/Default/StaticModelIcon.png b/Nu/Nu.Template.ImSim.Empty/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Nu/Nu.Template.ImSim.Empty/Assets/Default/StaticModelIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Empty/Assets/Default/TileMapIcon.png b/Nu/Nu.Template.ImSim.Empty/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Nu/Nu.Template.ImSim.Empty/Assets/Default/TileMapIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Game/Assets/Default/AnimatedModelIcon.png b/Nu/Nu.Template.ImSim.Game/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Nu/Nu.Template.ImSim.Game/Assets/Default/AnimatedModelIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Nu/Nu.Template.ImSim.Game/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Template.ImSim.Game/Assets/Default/RawIcon.png b/Nu/Nu.Template.ImSim.Game/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Nu/Nu.Template.ImSim.Game/Assets/Default/RawIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Game/Assets/Default/SongIcon.png b/Nu/Nu.Template.ImSim.Game/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Nu/Nu.Template.ImSim.Game/Assets/Default/SongIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Game/Assets/Default/SoundIcon.png b/Nu/Nu.Template.ImSim.Game/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Nu/Nu.Template.ImSim.Game/Assets/Default/SoundIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Game/Assets/Default/SpineSkeletonIcon.png b/Nu/Nu.Template.ImSim.Game/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Nu/Nu.Template.ImSim.Game/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Game/Assets/Default/StaticModelIcon.png b/Nu/Nu.Template.ImSim.Game/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Nu/Nu.Template.ImSim.Game/Assets/Default/StaticModelIcon.png differ diff --git a/Nu/Nu.Template.ImSim.Game/Assets/Default/TileMapIcon.png b/Nu/Nu.Template.ImSim.Game/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Nu/Nu.Template.ImSim.Game/Assets/Default/TileMapIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/AnimatedModelIcon.png b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/AnimatedModelIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/RawIcon.png b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/RawIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/SongIcon.png b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/SongIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/SoundIcon.png b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/SoundIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/SpineSkeletonIcon.png b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/StaticModelIcon.png b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/StaticModelIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Empty/Assets/Default/TileMapIcon.png b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Empty/Assets/Default/TileMapIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Game/Assets/Default/AnimatedModelIcon.png b/Nu/Nu.Template.Mmcc.Game/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Game/Assets/Default/AnimatedModelIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Nu/Nu.Template.Mmcc.Game/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Template.Mmcc.Game/Assets/Default/RawIcon.png b/Nu/Nu.Template.Mmcc.Game/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Game/Assets/Default/RawIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Game/Assets/Default/SongIcon.png b/Nu/Nu.Template.Mmcc.Game/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Game/Assets/Default/SongIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Game/Assets/Default/SoundIcon.png b/Nu/Nu.Template.Mmcc.Game/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Game/Assets/Default/SoundIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Game/Assets/Default/SpineSkeletonIcon.png b/Nu/Nu.Template.Mmcc.Game/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Game/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Game/Assets/Default/StaticModelIcon.png b/Nu/Nu.Template.Mmcc.Game/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Game/Assets/Default/StaticModelIcon.png differ diff --git a/Nu/Nu.Template.Mmcc.Game/Assets/Default/TileMapIcon.png b/Nu/Nu.Template.Mmcc.Game/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Nu/Nu.Template.Mmcc.Game/Assets/Default/TileMapIcon.png differ diff --git a/Nu/Nu.Tests/Assets/Default/AnimatedModelIcon.png b/Nu/Nu.Tests/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Nu/Nu.Tests/Assets/Default/AnimatedModelIcon.png differ diff --git a/Nu/Nu.Tests/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Nu/Nu.Tests/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Nu/Nu.Tests/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Nu/Nu.Tests/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Nu/Nu.Tests/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Nu/Nu.Tests/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Nu/Nu.Tests/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Nu/Nu.Tests/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Nu/Nu.Tests/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Nu/Nu.Tests/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Nu/Nu.Tests/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Nu/Nu.Tests/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Tests/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Nu/Nu.Tests/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Nu/Nu.Tests/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Nu/Nu.Tests/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Nu/Nu.Tests/Assets/Default/RawIcon.png b/Nu/Nu.Tests/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Nu/Nu.Tests/Assets/Default/RawIcon.png differ diff --git a/Nu/Nu.Tests/Assets/Default/SongIcon.png b/Nu/Nu.Tests/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Nu/Nu.Tests/Assets/Default/SongIcon.png differ diff --git a/Nu/Nu.Tests/Assets/Default/SoundIcon.png b/Nu/Nu.Tests/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Nu/Nu.Tests/Assets/Default/SoundIcon.png differ diff --git a/Nu/Nu.Tests/Assets/Default/SpineSkeletonIcon.png b/Nu/Nu.Tests/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Nu/Nu.Tests/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Nu/Nu.Tests/Assets/Default/StaticModelIcon.png b/Nu/Nu.Tests/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Nu/Nu.Tests/Assets/Default/StaticModelIcon.png differ diff --git a/Nu/Nu.Tests/Assets/Default/TileMapIcon.png b/Nu/Nu.Tests/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Nu/Nu.Tests/Assets/Default/TileMapIcon.png differ diff --git a/Nu/Nu/AssetGraph/AssetTag.fs b/Nu/Nu/AssetGraph/AssetTag.fs index 9a5199865c..1e6118c159 100644 --- a/Nu/Nu/AssetGraph/AssetTag.fs +++ b/Nu/Nu/AssetGraph/AssetTag.fs @@ -128,14 +128,6 @@ module AssetTag = [] module AssetTagOperators = - /// Check two asset tags for equality. - let inline assetEq (left : AssetTag) (right : AssetTag) = - left = right - - /// Check two asset tags for inequality. - let inline assetNeq left right = - not (assetEq left right) - /// Make an asset tag. let asset<'a> packageName assetName : 'a AssetTag = AssetTag.make packageName assetName \ No newline at end of file diff --git a/Nu/Nu/Assimp/Assimp.fs b/Nu/Nu/Assimp/Assimp.fs index f008116664..a8429982cd 100644 --- a/Nu/Nu/Assimp/Assimp.fs +++ b/Nu/Nu/Assimp/Assimp.fs @@ -66,8 +66,7 @@ type RenderStyle = type NavShape = | EmptyNavShape | BoundsNavShape - | StaticModelNavShape - | StaticModelSurfaceNavShape + | ContourNavShape /// The batch phasing such involved in persisting OpenGL state. type [] BatchPhase = @@ -91,7 +90,7 @@ module Assimp = m.A3, m.B3, m.C3, m.D3, m.A4, m.B4, m.C4, m.D4) - let internal ComputePositionKeyFrameIndex (animationTime : single, keys : Assimp.VectorKey array) = + let internal ComputePositionKeyFrameIndex (animationTime : double, keys : Assimp.VectorKey array) = let last = dec keys.Length let mutable low = 0 let mutable high = last @@ -100,16 +99,16 @@ module Assimp = while low <= high && not found do let mid = (low + high) / 2 if mid < last then - let midTime = single keys.[inc mid].Time + let midTime = keys.[inc mid].Time if animationTime < midTime then high <- mid - 1 elif animationTime > midTime then low <- mid + 1 else found <- true; i <- mid else found <- true; i <- last if not found then - i <- if animationTime < single keys.[inc low].Time then low else dec low + i <- if animationTime < keys.[inc low].Time then low else dec low i - let internal ComputeRotationKeyFrameIndex (animationTime : single, keys : Assimp.QuaternionKey array) = + let internal ComputeRotationKeyFrameIndex (animationTime : double, keys : Assimp.QuaternionKey array) = let last = dec keys.Length let mutable low = 0 let mutable high = last @@ -118,16 +117,16 @@ module Assimp = while low <= high && not found do let mid = (low + high) / 2 if mid < last then - let midTime = single keys.[inc mid].Time + let midTime = keys.[inc mid].Time if animationTime < midTime then high <- mid - 1 elif animationTime > midTime then low <- mid + 1 else found <- true; i <- mid else found <- true; i <- last if not found then - i <- if animationTime < single keys.[inc low].Time then low else dec low + i <- if animationTime < keys.[inc low].Time then low else dec low i - let internal ComputeScalingKeyFrameIndex (animationTime : single, keys : Assimp.VectorKey array) = + let internal ComputeScalingKeyFrameIndex (animationTime : double, keys : Assimp.VectorKey array) = let last = dec keys.Length let mutable low = 0 let mutable high = last @@ -136,56 +135,56 @@ module Assimp = while low <= high && not found do let mid = (low + high) / 2 if mid < last then - let midTime = single keys.[inc mid].Time + let midTime = keys.[inc mid].Time if animationTime < midTime then high <- mid - 1 elif animationTime > midTime then low <- mid + 1 else found <- true; i <- mid else found <- true; i <- last if not found then - i <- if animationTime < single keys.[inc low].Time then low else dec low + i <- if animationTime < keys.[inc low].Time then low else dec low i - let internal InterpolatePosition (animationTime : single, positionKeys : Assimp.VectorKey array) = + let internal InterpolatePosition (animationTime : double, positionKeys : Assimp.VectorKey array) = if positionKeys.Length <> 1 then let positionIndex = ComputePositionKeyFrameIndex (animationTime, positionKeys) let positionIndexNext = inc positionIndex % positionKeys.Length let positionKey = positionKeys.[positionIndex] let positionKeyNext = positionKeys.[positionIndexNext] - let deltaTime = single (positionKeyNext.Time - positionKey.Time) - let factor = (animationTime - single positionKey.Time) / deltaTime + let deltaTime = positionKeyNext.Time - positionKey.Time + let factor = (animationTime - positionKey.Time) / deltaTime let start = positionKey.Value let stop = positionKeyNext.Value let delta = stop - start - start + factor * delta + start + single factor * delta else positionKeys.[0].Value - let internal InterpolateRotation (animationTime : single, rotationKeys : Assimp.QuaternionKey array) = + let internal InterpolateRotation (animationTime : double, rotationKeys : Assimp.QuaternionKey array) = if rotationKeys.Length <> 1 then let rotationIndex = ComputeRotationKeyFrameIndex (animationTime, rotationKeys) let rotationIndexNext = inc rotationIndex % rotationKeys.Length let rotationKey = rotationKeys.[rotationIndex] let rotationKeyNext = rotationKeys.[rotationIndexNext] - let deltaTime = single (rotationKeyNext.Time - rotationKey.Time) - let factor = (animationTime - single rotationKey.Time) / deltaTime + let deltaTime = rotationKeyNext.Time - rotationKey.Time + let factor = (animationTime - rotationKey.Time) / deltaTime let startRotation = rotationKey.Value let stopRotation = rotationKeyNext.Value - let result = Assimp.Quaternion.Slerp (startRotation, stopRotation, factor) + let result = Assimp.Quaternion.Slerp (startRotation, stopRotation, single factor) result.Normalize () result else rotationKeys.[0].Value - let internal InterpolateScaling (animationTime : single, scalingKeys : Assimp.VectorKey array) = + let internal InterpolateScaling (animationTime : double, scalingKeys : Assimp.VectorKey array) = if scalingKeys.Length <> 1 then let scalingIndex = ComputeScalingKeyFrameIndex (animationTime, scalingKeys) let scalingIndexNext = inc scalingIndex % scalingKeys.Length let scalingKey = scalingKeys.[scalingIndex] let scalingKeyNext = scalingKeys.[scalingIndexNext] - let deltaTime = single (scalingKeyNext.Time - scalingKey.Time) - let factor = (animationTime - single scalingKey.Time) / deltaTime + let deltaTime = scalingKeyNext.Time - scalingKey.Time + let factor = (animationTime - scalingKey.Time) / deltaTime let start = scalingKey.Value let stop = scalingKeyNext.Value let delta = stop - start - start + factor * delta + start + single factor * delta else scalingKeys.[0].Value [] @@ -229,12 +228,6 @@ module AssimpExtensions = NodeName : string HashCode : int } - static member make animationName nodeName = - let hashCode = hash animationName ^^^ hash nodeName - { AnimationName = animationName - NodeName = nodeName - HashCode = hashCode } - static member equals left right = left.AnimationName = right.AnimationName && left.NodeName = right.NodeName @@ -242,6 +235,12 @@ module AssimpExtensions = static member hash key = key.HashCode + static member make animationName nodeName = + let hashCode = hash animationName ^^^ hash nodeName + { AnimationName = animationName + NodeName = nodeName + HashCode = hashCode } + override this.Equals thatObj = match thatObj with | :? AnimationChannelKey as that -> AnimationChannelKey.equals this that @@ -568,7 +567,7 @@ module AssimpExtensions = List.tryHead nodes static member private UpdateBoneTransforms - (time : single, + (time : double, boneIds : Dictionary, boneInfos : BoneInfo array, boneWrites : int ref, // OPTIMIZATION: bones writes counter prevents us from traversing nodes in the hierarchy that would be redundant (once per duplicated armature). @@ -584,21 +583,22 @@ module AssimpExtensions = for animation in animations do let animationStartTime = animation.StartTime.Seconds let animationLifeTimeOpt = Option.map (fun (lifeTime : GameTime) -> lifeTime.Seconds) animation.LifeTimeOpt + let animationRate = animation.Rate * Constants.Render.AnimatedModelRateScalar let mutable animationChannel = Unchecked.defaultof<_> if animationChannels.TryGetValue (AnimationChannelKey.make animation.Name node.Name, &animationChannel) then - let localTime = max 0.0f (time - animationStartTime) + let localTime = max 0.0 (time - animationStartTime) if (match animationLifeTimeOpt with Some lifeTime -> localTime < animationStartTime + lifeTime | None -> true) && (match animation.BoneFilterOpt with Some boneFilter -> boneFilter.Contains node.Name | None -> true) then let localTimeScaled = match animation.Playback with | Once -> - localTime * animation.Rate * Constants.Render.AnimatedModelRateScalar + localTime * double animationRate | Loop -> - let length = single animationChannel.RotationKeys.[dec animationChannel.RotationKeys.Length].Time - localTime * animation.Rate * Constants.Render.AnimatedModelRateScalar % length + let length = animationChannel.RotationKeys.[dec animationChannel.RotationKeys.Length].Time + localTime * double animationRate % length | Bounce -> - let length = single animationChannel.RotationKeys.[dec animationChannel.RotationKeys.Length].Time - let localTimeScaled = localTime * animation.Rate * Constants.Render.AnimatedModelRateScalar + let length = animationChannel.RotationKeys.[dec animationChannel.RotationKeys.Length].Time + let localTimeScaled = localTime * double animationRate let remainingTime = localTimeScaled % length if int (localTimeScaled / length) % 2 = 1 then length - remainingTime diff --git a/Nu/Nu/Audio/AudioPlayer.fs b/Nu/Nu/Audio/AudioPlayer.fs index 9da3e27ccd..143e756287 100644 --- a/Nu/Nu/Audio/AudioPlayer.fs +++ b/Nu/Nu/Audio/AudioPlayer.fs @@ -10,9 +10,21 @@ open Prime /// Describes a sound. type SoundDescriptor = - { Volume : single + { Distance : single + Panning : single + Volume : single Sound : Sound AssetTag } + // OPTIMIZATION: instantiate once. + static let DefaultDescriptor = + { Distance = 0.0f + Panning = 0.0f + Volume = Constants.Audio.SoundVolumeDefault + Sound = asset Assets.Default.PackageName Assets.Default.SoundName } + + /// The default sound descriptor. + static member defaultDescriptor = DefaultDescriptor + /// Describes a song. type SongDescriptor = { FadeInTime : GameTime @@ -22,6 +34,18 @@ type SongDescriptor = Volume : single Song : Song AssetTag } + // OPTIMIZATION: instantiate once. + static let DefaultDescriptor = + { FadeInTime = GameTime.zero + FadeOutTime = Constants.Audio.FadeOutTimeDefault + StartTime = GameTime.zero + RepeatLimitOpt = None + Volume = Constants.Audio.SongVolumeDefault + Song = asset Assets.Default.PackageName Assets.Default.SongName } + + /// The default song descriptor. + static member defaultDescriptor = DefaultDescriptor + /// A message to the audio system. type AudioMessage = | LoadAudioPackageMessage of string @@ -244,10 +268,10 @@ type [] SdlAudioPlayer = let loops = match playSongMessage.RepeatLimitOpt with Some repeatLimit -> max 0 (int repeatLimit) | None -> -1 SDL_mixer.Mix_HaltMusic () |> ignore // NOTE: have to stop current song in case it is still fading out, causing the next song not to play. SDL_mixer.Mix_VolumeMusic (int (playSongMessage.Volume * audioPlayer.MasterAudioVolume * audioPlayer.MasterSongVolume * single SDL_mixer.MIX_MAX_VOLUME)) |> ignore - match SDL_mixer.Mix_FadeInMusicPos (musAsset, loops, int (max Constants.Audio.FadeInSecondsMin playSongMessage.FadeInTime.Seconds * 1000.0f), double playSongMessage.StartTime.Seconds) with + match SDL_mixer.Mix_FadeInMusicPos (musAsset, loops, int (max Constants.Audio.FadeInSecondsMin playSongMessage.FadeInTime.Seconds * 1000.0), double playSongMessage.StartTime.Seconds) with | -1 -> // HACK: start time exceeded length of track, so starting over. - SDL_mixer.Mix_FadeInMusicPos (musAsset, loops, int (max Constants.Audio.FadeInSecondsMin playSongMessage.FadeInTime.Seconds * 1000.0f), 0.0) |> ignore + SDL_mixer.Mix_FadeInMusicPos (musAsset, loops, int (max Constants.Audio.FadeInSecondsMin playSongMessage.FadeInTime.Seconds * 1000.0), 0.0) |> ignore | _ -> () audioPlayer.SongOpt <- Some (playSongMessage, musAsset) | None -> @@ -276,7 +300,13 @@ type [] SdlAudioPlayer = match audioAsset with | WavAsset wavAsset -> SDL_mixer.Mix_VolumeChunk (wavAsset, int (playSoundMessage.Volume * audioPlayer.MasterSoundVolume * single SDL_mixer.MIX_MAX_VOLUME)) |> ignore - SDL_mixer.Mix_PlayChannel (-1, wavAsset, 0) |> ignore + let channel = SDL_mixer.Mix_PlayChannel (-1, wavAsset, 0) + let pan = playSoundMessage.Panning |> max -1.0f |> min 1.0f + let left = byte (255.0f * (1.0f - max 0.0f pan)) + let right = byte (255.0f * (1.0f + min 0.0f pan)) + SDL_mixer.Mix_SetPanning (channel, left, right) |> ignore + let distance = playSoundMessage.Distance |> max 0.0f |> min 1.0f |> (*) 255.0f |> byte + SDL_mixer.Mix_SetDistance (channel, distance) |> ignore | MusAsset _ -> Log.info ("Cannot play song asset as sound '" + scstring sound + "'.") | None -> Log.info ("PlaySoundMessage failed due to unloadable assets for '" + scstring sound + "'.") @@ -288,7 +318,7 @@ type [] SdlAudioPlayer = if SDL_mixer.Mix_PlayingMusic () = 1 then if fadeOutTime <> GameTime.zero && SDL_mixer.Mix_FadingMusic () <> SDL_mixer.Mix_Fading.MIX_FADING_OUT then - SDL_mixer.Mix_FadeOutMusic (int (fadeOutTime.Seconds * 1000.0f)) |> ignore + SDL_mixer.Mix_FadeOutMusic (int (fadeOutTime.Seconds * 1000.0)) |> ignore else SDL_mixer.Mix_HaltMusic () |> ignore diff --git a/Nu/Nu/Core/Assets.fs b/Nu/Nu/Core/Assets.fs index 0c47776cc4..3e72274ee7 100644 --- a/Nu/Nu/Core/Assets.fs +++ b/Nu/Nu/Core/Assets.fs @@ -2,6 +2,7 @@ // Copyright (C) Bryan Edds. namespace Nu +open Prime /// Active patterns for recognizing asset file extensions. [] @@ -93,4 +94,20 @@ module Assets = let [] LightProbeModelName = "LightProbeModel" let [] AnimatedModelName = "AnimatedModel" let [] SoundName = "Sound" - let [] SongName = "Song" \ No newline at end of file + let [] SongName = "Song" + let [] RawIconName = "RawIcon" + let [] TileMapIconName = "TileMapIcon" + let [] SpineSkeletonIconName = "SpineSkeletonIcon" + let [] StaticModelIconName = "StaticModelIcon" + let [] AnimatedModelIconName = "AnimatedModelIcon" + let [] SoundIconName = "SoundIcon" + let [] SongIconName = "SongIcon" + let [] IconNames = + Set.ofList + [RawIconName + TileMapIconName + SpineSkeletonIconName + StaticModelIconName + AnimatedModelIconName + SoundIconName + SongIconName] \ No newline at end of file diff --git a/Nu/Nu/Core/Behavior.fs b/Nu/Nu/Core/Behavior.fs index 9c5686e647..b7d9716a11 100644 --- a/Nu/Nu/Core/Behavior.fs +++ b/Nu/Nu/Core/Behavior.fs @@ -167,7 +167,7 @@ module Behavior = map (fun a -> let local = a % stride if bounce then - if int (a / stride) % 2 = 0 + if int64 (a / stride) % 2L = 0L then local else stride - local else local) diff --git a/Nu/Nu/Core/Constants.fs b/Nu/Nu/Core/Constants.fs index 2bce4c474e..48dc8d462c 100644 --- a/Nu/Nu/Core/Constants.fs +++ b/Nu/Nu/Core/Constants.fs @@ -211,8 +211,8 @@ module Render = let [] LightsMaxForward = 9 // NOTE: remember to update LIGHTS_MAX in forward shaders when changing this! let [] mutable ShadowVirtualResolution = match ConfigurationManager.AppSettings.["ShadowVirtualResolution"] with null -> 256 | value -> scvalue value let [] mutable ShadowDisplayScalarMax = match ConfigurationManager.AppSettings.["ShadowDisplayScalarMax"] with null -> 4 | value -> scvalue value - let [] ShadowTexturesMax = 9 // NOTE: remember to update SHADOW_TEXTURES_MAX in shaders when changing this! - let [] ShadowMapsMax = 9 // NOTE: remember to update SHADOW_MAPS_MAX in shaders when changing this! + let [] ShadowTexturesMax = 12 // NOTE: remember to update SHADOW_TEXTURES_MAX in shaders when changing this! + let [] ShadowMapsMax = 12 // NOTE: remember to update SHADOW_MAPS_MAX in shaders when changing this! let [] mutable ShadowDirectionalMarginRatioCull = match ConfigurationManager.AppSettings.["ShadowDirectionalMarginRatioCull"] with null -> 0.5f | value -> scvalue value let [] ShadowCascadesMax = 2 // NOTE: remember to update SHADOW_CASCADES_MAX in shaders when changing this! let [] ShadowCascadeLevels = 3 // NOTE: remember to update SHADOW_CASCADE_LEVELS_SIZE in shaders when changing this! @@ -330,11 +330,11 @@ module Audio = let [] MasterSongVolumeDefault = 1.0f let [] SoundVolumeDefault = 1.0f let [] SongVolumeDefault = 1.0f - let [] FadeOutTimeDefault = GameTime.ofSeconds 0.5f - let [] SongResumptionMax = GameTime.ofSeconds 90.0f // HACK: prevents songs from starting over too often due to hack in SdlAudioPlayer.playSong. + let [] FadeOutTimeDefault = GameTime.ofSeconds 0.5 + let [] SongResumptionMax = GameTime.ofSeconds 90.0 // HACK: prevents songs from starting over too often due to hack in SdlAudioPlayer.playSong. let [] Frequency = 44100 let [] BufferSize = 1024 - let [] FadeInSecondsMin = 0.1f // NOTE: Mix_FadeInMusicPos seems to sometimes cause audio 'popping' when starting a song, so a minimum fade is used instead. + let [] FadeInSecondsMin = 0.1 // NOTE: Mix_FadeInMusicPos seems to sometimes cause audio 'popping' when starting a song, so a minimum fade is used instead. [] module Physics = @@ -343,8 +343,8 @@ module Physics = let [] FrictionDefault = 0.5f let [] AngularDampingDefault = 0.2f let [] CollisionWildcard = "*" - let [] mutable PhysicsEngine2d = match ConfigurationManager.AppSettings.["PhysicsEngine2d"] with null -> Aether | value -> scvalue value let [] mutable Collision2dSteps = match ConfigurationManager.AppSettings.["Collision2dSteps"] with null -> 4 | value -> scvalue value + let [] mutable Collision2dFrameCompensation = match ConfigurationManager.AppSettings.["Collision2dFrameCompensation"] with null -> false | value -> scvalue value let [] mutable Collision3dBodiesMax = match ConfigurationManager.AppSettings.["Collision3dBodiesMax"] with null -> 65536 | value -> scvalue value let [] mutable Collision3dBodyPairsMax = match ConfigurationManager.AppSettings.["Collision3dBodyPairsMax"] with null -> 32768 | value -> scvalue value let [] mutable Collision3dContactConstraintsMax = match ConfigurationManager.AppSettings.["Collision3dContactConstraintsMax"] with null -> 16384 | value -> scvalue value diff --git a/Nu/Nu/Core/EventFilter.fs b/Nu/Nu/Core/EventFilter.fs index f0d84e4bd9..cfd8f2137e 100644 --- a/Nu/Nu/Core/EventFilter.fs +++ b/Nu/Nu/Core/EventFilter.fs @@ -47,7 +47,7 @@ and [)>] Rexpr (pattern) = member this.Pattern = pattern override this.Equals that = match that with - | :? Rexpr as that -> strEq this.Pattern that.Pattern + | :? Rexpr as that -> this.Pattern = that.Pattern | _ -> false override this.GetHashCode () = hash pattern diff --git a/Nu/Nu/Core/GameTime.fs b/Nu/Nu/Core/GameTime.fs index 98429b0b0b..eafb40a9ea 100644 --- a/Nu/Nu/Core/GameTime.fs +++ b/Nu/Nu/Core/GameTime.fs @@ -44,7 +44,7 @@ type GameTimeConverter () = let gameTime = source :?> GameTime match gameTime with | UpdateTime time -> Number (string time, ValueNone) :> obj - | TickTime time -> Number (string (single time / single Stopwatch.Frequency), ValueNone) :> obj + | TickTime time -> Number (string (double time / double Stopwatch.Frequency), ValueNone) :> obj elif destType = typeof then source else failconv "Invalid GameTimeConverter conversion to source." None @@ -59,7 +59,7 @@ type GameTimeConverter () = | Number (time, _) -> match Constants.GameTime.DesiredFrameRate with | StaticFrameRate _ -> UpdateTime (Int64.Parse time) :> obj - | DynamicFrameRate _ -> TickTime (int64 (Single.Parse time * single Stopwatch.Frequency)) :> obj + | DynamicFrameRate _ -> TickTime (int64 (Double.Parse time * double Stopwatch.Frequency)) :> obj | _ -> failconv "Invalid GameTimeConverter conversion from source." (Some symbol) | :? GameTime -> source | _ -> failconv "Invalid GameTimeConverter conversion from source." None @@ -98,40 +98,40 @@ and [ failwith "Cannot apply operation to mixed GameTimes." /// Construct a game time from updates or clock time. - static member make updateTime (clockTime : single) = + static member make updateTime (clockTime : double) = match Constants.GameTime.DesiredFrameRate with | StaticFrameRate _ -> UpdateTime updateTime - | DynamicFrameRate _ -> TickTime (int64 (clockTime * single Stopwatch.Frequency)) + | DynamicFrameRate _ -> TickTime (int64 (clockTime * double Stopwatch.Frequency)) /// Construct a game time from a number of updates assuming desired frame rate is met. static member ofUpdates updates = match Constants.GameTime.DesiredFrameRate with | StaticFrameRate _ -> UpdateTime updates - | DynamicFrameRate frameRate -> TickTime (int64 (1.0f / single frameRate * single updates * single Stopwatch.Frequency)) + | DynamicFrameRate frameRate -> TickTime (int64 (1.0 / double frameRate * double updates * double Stopwatch.Frequency)) /// Construct a game time from an amount of seconds assuming desired frame rate was met. static member ofSeconds seconds = match Constants.GameTime.DesiredFrameRate with - | StaticFrameRate frameRate -> UpdateTime (int64 (single frameRate * seconds)) - | DynamicFrameRate _ -> TickTime (int64 (seconds * single Stopwatch.Frequency)) + | StaticFrameRate frameRate -> UpdateTime (int64 (double frameRate * seconds)) + | DynamicFrameRate _ -> TickTime (int64 (seconds * double Stopwatch.Frequency)) /// Get the number of updates assuming desired frame rate is met. static member toUpdates time = match struct (Constants.GameTime.DesiredFrameRate, time) with | struct (_, UpdateTime time) -> time - | struct (DynamicFrameRate frameRate, TickTime time) -> int64 (single time / (1.0f / single frameRate)) + | struct (DynamicFrameRate frameRate, TickTime time) -> int64 (double time / (1.0 / double frameRate)) | struct (_, _) -> failwith "Cannot apply operation to mixed GameTimes." /// Get the total amount of seconds assuming desired frame rate is met. static member toSeconds time = match struct (Constants.GameTime.DesiredFrameRate, time) with - | struct (StaticFrameRate frameRate, UpdateTime time) -> 1.0f / single frameRate * single time - | struct (_, TickTime time) -> single time / single Stopwatch.Frequency + | struct (StaticFrameRate frameRate, UpdateTime time) -> 1.0 / double frameRate * double time + | struct (_, TickTime time) -> double time / double Stopwatch.Frequency | struct (_, _) -> failwith "Cannot apply operation to mixed GameTimes." /// Get the total amount of milliseconds assuming desired frame rate is met. static member toMilliseconds time = - GameTime.toSeconds time * 1000.0f + GameTime.toSeconds time * 1000.0 /// Equate GameTimes. static member equals left right = @@ -144,46 +144,59 @@ and [ if leftTime < rightTime then -1 elif leftTime > rightTime then 1 else 0 | struct (_, _) -> failwith "Cannot apply operation to mixed GameTimes." - /// The progress of time down a bounded time range. + /// The progress of time down a unit-bounded range (double precision). static member progress startTime currentTime lifeTime = match struct (startTime, currentTime, lifeTime) with - | struct (UpdateTime startTime, UpdateTime currentTime, UpdateTime lifeTime) -> (single (currentTime - startTime)) / single lifeTime |> max 0.0f |> min 1.0f - | struct (TickTime startTime, TickTime currentTime, TickTime lifeTime) -> single (currentTime - startTime) / single lifeTime |> max 0.0f |> min 1.0f + | struct (UpdateTime startTime, UpdateTime currentTime, UpdateTime lifeTime) -> double (currentTime - startTime) / double lifeTime |> max 0.0 |> min 1.0 + | struct (TickTime startTime, TickTime currentTime, TickTime lifeTime) -> double (currentTime - startTime) / double lifeTime |> max 0.0 |> min 1.0 | struct (_, _, _) -> failwith "Cannot apply operation to mixed GameTimes." + /// The progress of time down a unit-bounded range (single precision). + /// NOTE: this loses some very minor precision but is fine for casual use. + static member progressF startTime currentTime lifeTime = + single (GameTime.progress startTime currentTime lifeTime) + static member (+) (left, right) = GameTime.ap (+) (+) left right static member (-) (left, right) = GameTime.ap (-) (-) left right static member (*) (left, right) = GameTime.ap (*) (fun left right -> (left / Stopwatch.Frequency) * (right / Stopwatch.Frequency) / Stopwatch.Frequency |> int64) left right static member (/) (left, right) = GameTime.ap (/) (fun left right -> left / right * Stopwatch.Frequency |> int64) left right static member (%) (left, right) = GameTime.ap (%) (fun left right -> left % right) left right static member op_Implicit (i : int64) = UpdateTime i - static member op_Implicit (s : single) = TickTime (int64 (s * single Stopwatch.Frequency)) - static member op_Explicit time = match time with UpdateTime time -> int time | TickTime time -> int (single time / single Stopwatch.Frequency) - static member op_Explicit time = match time with UpdateTime time -> int64 time | TickTime time -> int64 (single time / single Stopwatch.Frequency) - static member op_Explicit time = match time with UpdateTime time -> single time | TickTime time -> single (single time / single Stopwatch.Frequency) - static member op_Explicit time = match time with UpdateTime time -> double time | TickTime time -> double (single time / single Stopwatch.Frequency) + static member op_Implicit (d : double) = TickTime (int64 (d * double Stopwatch.Frequency)) + static member op_Explicit time = match time with UpdateTime time -> int64 time | TickTime time -> int64 (double time / double Stopwatch.Frequency) + static member op_Explicit time = match time with UpdateTime time -> double time | TickTime time -> double (double time / double Stopwatch.Frequency) static member get_Zero () = GameTime.zero static member isZero time = GameTime.unary isZero isZero time static member notZero time = GameTime.unary notZero notZero time - static member zero = GameTime.ofSeconds 0.0f + static member zero = GameTime.ofSeconds 0.0 static member epsilon = match Constants.GameTime.DesiredFrameRate with StaticFrameRate _ -> UpdateTime 1L | DynamicFrameRate _ -> TickTime 1L static member min (left : GameTime) right = if left <= right then left else right static member max (left : GameTime) right = if left >= right then left else right - static member MinValue = GameTime.make Int64.MinValue Single.MinValue - static member MaxValue = GameTime.make Int64.MaxValue Single.MaxValue + static member MinValue = GameTime.make Int64.MinValue Double.MinValue + static member MaxValue = GameTime.make Int64.MaxValue Double.MaxValue /// The total amount of elapsed updates. member this.Updates = GameTime.toUpdates this - /// The total amount of elapsed seconds. + /// The total amount of elapsed seconds (double precision). member this.Seconds = GameTime.toSeconds this - /// The total amount of elapsed milliseconds. + /// The total amount of elapsed seconds (single precision). + /// NOTE: this loses precision for large GameTime values, such as a span of hours. + member this.SecondsF = + single this.Seconds + + /// The total amount of elapsed milliseconds (double precision). member this.Milliseconds = GameTime.toMilliseconds this + /// The total amount of elapsed milliseconds (single precision). + /// NOTE: this loses precision for large GameTime values, such as a span of hours. + member this.MillisecondsF = + single this.Milliseconds + /// Check that the game time represents zero time. member this.IsZero = GameTime.isZero this diff --git a/Nu/Nu/Core/Math.fs b/Nu/Nu/Core/Math.fs index 1052286be9..c5498f0413 100644 --- a/Nu/Nu/Core/Math.fs +++ b/Nu/Nu/Core/Math.fs @@ -61,8 +61,6 @@ module Vector2 = a.Rotate r let inline v2 x y = Vector2 (x, y) - let inline v2Eq (v : Vector2) (v2 : Vector2) = v.X = v2.X && v.Y = v2.Y - let inline v2Neq (v : Vector2) (v2 : Vector2) = v.X <> v2.X || v.Y <> v2.Y let v2EqApprox (v : Vector2) (v2 : Vector2) epsilon = Math.ApproximatelyEqual (v.X, v2.X, epsilon) && Math.ApproximatelyEqual (v.Y, v2.Y, epsilon) @@ -200,8 +198,6 @@ module Vector3 = -Vector3.ToPlane (v, p) let inline v3 x y z = Vector3 (x, y, z) - let inline v3Eq (v : Vector3) (v2 : Vector3) = v.X = v2.X && v.Y = v2.Y && v.Z = v2.Z - let inline v3Neq (v : Vector3) (v2 : Vector3) = v.X <> v2.X || v.Y <> v2.Y || v.Z <> v2.Z let v3EqApprox (v : Vector3) (v2 : Vector3) epsilon = Math.ApproximatelyEqual (v.X, v2.X, epsilon) && Math.ApproximatelyEqual (v.Y, v2.Y, epsilon) && @@ -295,8 +291,6 @@ module Vector4 = a.W % b.W) let inline v4 x y z w = Vector4 (x, y, z, w) - let inline v4Eq (v : Vector4) (v2 : Vector4) = v.X = v2.X && v.Y = v2.Y && v.Z = v2.Z && v.W = v2.W - let inline v4Neq (v : Vector4) (v2 : Vector4) = v.X <> v2.X || v.Y <> v2.Y || v.Z <> v2.Z || v.W <> v2.W let v4EqApprox (v : Vector4) (v2 : Vector4) epsilon = Math.ApproximatelyEqual (v.X, v2.X, epsilon) && Math.ApproximatelyEqual (v.Y, v2.Y, epsilon) && @@ -370,8 +364,6 @@ module Vector2i = a.Y % b.Y) let inline v2i x y = Vector2i (x, y) - let inline v2iEq (v : Vector2i) (v2 : Vector2i) = v.X = v2.X && v.Y = v2.Y - let inline v2iNeq (v : Vector2i) (v2 : Vector2i) = v.X <> v2.X || v.Y <> v2.Y let inline v2iDup (a : int) = v2i a a let v2iOne = Vector2i.One let v2iZero = Vector2i.Zero @@ -440,8 +432,6 @@ module Vector3i = a.Z % b.Z) let inline v3i x y z = Vector3i (x, y, z) - let inline v3iEq (v : Vector3i) (v2 : Vector3i) = v.X = v2.X && v.Y = v2.Y && v.Z = v2.Z - let inline v3iNeq (v : Vector3i) (v2 : Vector3i) = v.X <> v2.X || v.Y <> v2.Y || v.Z <> v2.Z let inline v3iDup (a : int) = v3i a a a let v3iOne = Vector3i.One let v3iZero = Vector3i.Zero @@ -521,8 +511,6 @@ module Vector4i = a.W % b.W) let inline v4i x y z w = Vector4i (x, y, z, w) - let inline v4iEq (v : Vector4i) (v2 : Vector4i) = v.X = v2.X && v.Y = v2.Y && v.Z = v2.Z && v.W = v2.W - let inline v4iNeq (v : Vector4i) (v2 : Vector4i) = v.X <> v2.X || v.Y <> v2.Y || v.Z <> v2.Z || v.W <> v2.W let inline v4iDup (a : int) = v4i a a a a let v4iOne = Vector4i.One let v4iZero = Vector4i.Zero @@ -663,8 +651,6 @@ module Quaternion = let quatIdentity = Quaternion.Identity let inline quat x y z w = Quaternion (x, y, z, w) - let inline quatEq (q : Quaternion) (q2 : Quaternion) = q.Equals q2 - let inline quatNeq (q : Quaternion) (q2 : Quaternion) = not (q.Equals q2) let quatEqApprox (v : Quaternion) (v2 : Quaternion) epsilon = Math.ApproximatelyEqual (v.X, v2.X, epsilon) && Math.ApproximatelyEqual (v.Y, v2.Y, epsilon) && @@ -735,8 +721,6 @@ module Box2 = let box2Zero = Box2.Zero let inline box2 min size = Box2 (min, size) - let inline box2Eq (b : Box2) (b2 : Box2) = b.Equals b2 - let inline box2Neq (b : Box2) (b2 : Box2) = not (b.Equals b2) let box2Slice sliceIndex (sliceMargin : Vector2) (perimeter : Box2) = match sliceIndex with @@ -881,8 +865,6 @@ module Box3 = let box3Zero = Box3.Zero let inline box3 min size = Box3 (min, size) - let inline box3Eq (b : Box3) (b2 : Box3) = b.Equals b2 - let inline box3Neq (b : Box3) (b2 : Box3) = not (b.Equals b2) let box3Slice sliceIndex sliceMargins (perimeter : Box3) = (box2Slice sliceIndex sliceMargins perimeter.Box2).Box3 let box3SliceInverted sliceIndex sliceMargins (perimeter : Box3) = (box2SliceInverted sliceIndex sliceMargins perimeter.Box2).Box3 @@ -948,8 +930,6 @@ module Box2i = let box2iZero = Box2i.Zero let inline box2i min size = Box2i (min, size) - let inline box2iEq (b : Box2i) (b2 : Box2i) = b.Equals b2 - let inline box2iNeq (b : Box2i) (b2 : Box2i) = not (b.Equals b2) /// Converts Box2i types. type Box2iConverter () = @@ -1014,8 +994,6 @@ module Box3i = let box3iZero = Box3i.Zero let inline box3i min size = Box3i (min, size) - let inline box3iEq (b : Box3i) (b2 : Box3i) = b.Equals b2 - let inline box3iNeq (b : Box3i) (b2 : Box3i) = not (b.Equals b2) /// Converts Box3i types. type Box3iConverter () = @@ -1128,8 +1106,6 @@ module Matrix3x2 = r1.X, r1.Y, r2.X, r2.Y) - let inline m3x2Eq (x : Matrix3x2) (y : Matrix3x2) = x.Equals y - let inline m3x2Neq (x : Matrix3x2) (y : Matrix3x2) = not (x.Equals y) let m3x2Identity = Matrix3x2.Identity let m3x2Zero = Unchecked.defaultof @@ -1258,8 +1234,6 @@ module Matrix4x4 = r2.X, r2.Y, r2.Z, r2.W, r3.X, r3.Y, r3.Z, r3.W) - let inline m4Eq (x : Matrix4x4) (y : Matrix4x4) = x.Equals y - let inline m4Neq (x : Matrix4x4) (y : Matrix4x4) = not (x.Equals y) let m4Identity = Matrix4x4.Identity let m4Zero = Unchecked.defaultof @@ -1328,8 +1302,6 @@ module Color = let inline color8 (r : byte) (g : byte) (b : byte) (a : byte) = Color (r, g, b, a) let inline color8Dup (a : byte) = color8 a a a a let inline colorPacked (u : uint) = Color u - let inline colorEq (x : Color) (y : Color) = x.R = y.R && x.G = y.G && x.B = y.B && x.A = y.A - let inline colorNeq (x : Color) (y : Color) = x.R <> y.R || x.G <> y.G || x.B <> y.B || x.A <> y.A let colorZero = Color.Zero let colorOne = Color.One @@ -1410,8 +1382,6 @@ type Segment2Converter () = module Segment2 = let inline segment2 (a : Vector2) (b : Vector2) = Segment2 (a, b) - let inline segment2Eq (left : Segment2) (right : Segment2) = left.Equals right - let inline segment2Neq (left : Segment2) (right : Segment2) = not (left.Equals right) type Segment2 with member this.Magnitude = this.Length () @@ -1457,8 +1427,6 @@ type Segment3Converter () = module Segment3 = let inline segment3 (a : Vector3) (b : Vector3) = Segment3 (a, b) - let inline segment3Eq (left : Segment3) (right : Segment3) = left.Equals right - let inline segment3Neq (left : Segment3) (right : Segment3) = not (left.Equals right) type Segment3 with member this.Magnitude = this.Length () @@ -1469,16 +1437,12 @@ module Segment3 = module Ray2 = let inline ray2 (origin : Vector2) (direction : Vector2) = Ray2 (origin, direction) - let inline ray2Eq (left : Ray2) (right : Ray2) = left.Equals right - let inline ray2Neq (left : Ray2) (right : Ray2) = not (left.Equals right) // TODO: create symbolic converter for Ray3. [] module Ray3 = let inline ray3 (origin : Vector3) (direction : Vector3) = Ray3 (origin, direction) - let inline ray3Eq (left : Ray3) (right : Ray3) = left.Equals right - let inline ray3Neq (left : Ray3) (right : Ray3) = not (left.Equals right) // TODO: create symbolic converter for Plane3. [] @@ -1486,8 +1450,6 @@ module Plane3 = let inline plane3 (pointOnPlane : Vector3) (normal : Vector3) = Plane3 (pointOnPlane, normal) let inline plane3Equation (normal : Vector3) (d : single) = Plane3 (normal, d) - let inline plane3Eq (left : Plane3) (right : Plane3) = left.Equals right - let inline plane3Neq (left : Plane3) (right : Plane3) = not (left.Equals right) type Plane3 with @@ -1724,11 +1686,6 @@ type [] ScatterType = | FoliageScatter -> 0.2f | WaxScatter -> 0.3f -/// The type of 2D physics engine to use. -type [] PhysicsEngine2dType = - | Aether - | Box2dNet - [] module Math = diff --git a/Nu/Nu/Effects/EffectSystem.fs b/Nu/Nu/Effects/EffectSystem.fs index 5a57a2c777..b52e15fc0c 100644 --- a/Nu/Nu/Effects/EffectSystem.fs +++ b/Nu/Nu/Effects/EffectSystem.fs @@ -53,7 +53,7 @@ module EffectSystem = let totalTime = Array.fold (fun totalTime (keyFrame : 'kf) -> totalTime + keyFrame.KeyFrameLength) GameTime.zero keyFrames if totalTime <> GameTime.zero then let moduloTime = localTime % totalTime - let bouncing = int (localTime / totalTime) % 2 = 1 + let bouncing = int64 (localTime / totalTime) % 2L = 1L let bounceTime = if bouncing then totalTime - moduloTime else moduloTime selectKeyFrames2 bounceTime Once keyFrames else (GameTime.zero, Array.head keyFrames, Array.head keyFrames) @@ -125,20 +125,20 @@ module EffectSystem = let private evalInset (celSize : Vector2i) celCount celRun delay playback effectSystem = // TODO: stop assuming that animation sheets are fully and evenly populated when flipping! - let celUnmodulated = int (effectSystem.EffectTime / delay) + let celUnmodulated = int64 (effectSystem.EffectTime / delay) let cel = celUnmodulated % celCount let celI = cel % celRun let celJ = cel / celRun let bouncing = match playback with - | Bounce -> celUnmodulated % (celCount * 2) >= celCount + | Bounce -> celUnmodulated % (celCount * 2L) >= celCount | Once | Loop -> false let (celI, celJ) = if bouncing then (celRun - celI, (celRun % celCount) - celJ) else (celI, celJ) - let celX = celI * celSize.X - let celY = celJ * celSize.Y + let celX = celI * int64 celSize.X + let celY = celJ * int64 celSize.Y let celPosition = Vector2 (single celX, single celY) let celSize = Vector2 (single celSize.X, single celSize.Y) Box2 (celPosition, celSize) @@ -177,7 +177,7 @@ module EffectSystem = evalContent content slice history effectSystem and private evalProgress keyFrameTime keyFrameLength effectSystem = - let progress = if GameTime.isZero keyFrameLength then 1.0f else single keyFrameTime / single keyFrameLength + let progress = if GameTime.isZero keyFrameLength then 1.0f else single (double keyFrameTime / double keyFrameLength) let progress = progress + effectSystem.EffectProgressOffset if progress > 1.0f then progress - 1.0f else progress @@ -406,7 +406,7 @@ module EffectSystem = if GameTime.notZero delay && celRun <> 0 then // compute cel - let cel = int (effectSystem.EffectTime / delay) + let cel = int64 (effectSystem.EffectTime / delay) // eval inset let inset = evalInset celSize celCount celRun delay playback effectSystem @@ -653,8 +653,8 @@ module EffectSystem = let effectTime = effectSystem.EffectTimeOriginal - slice.SliceTime let slice = { slice with Elevation = slice.Elevation + shift } let slice = evalAspects emitterAspects slice { effectSystem with EffectTime = effectSystem.EffectTime - effectTime } - let emitCountLastFrame = single (effectSystem.EffectTime - effectTime - slice.SliceDelta) * rate - let emitCountThisFrame = single (effectSystem.EffectTime - effectTime) * rate + let emitCountLastFrame = double (effectSystem.EffectTime - effectTime - slice.SliceDelta) * double rate + let emitCountThisFrame = double (effectSystem.EffectTime - effectTime) * double rate let emitCount = int emitCountThisFrame - int emitCountLastFrame let effectSystem = Array.fold (fun effectSystem _ -> diff --git a/Nu/Nu/ImGui/ImGui.fs b/Nu/Nu/ImGui/ImGui.fs index 56bf55ad8d..23b1fab5fb 100644 --- a/Nu/Nu/ImGui/ImGui.fs +++ b/Nu/Nu/ImGui/ImGui.fs @@ -179,8 +179,8 @@ type ImGui (stub : bool, displaySize : Vector2i) = colors.[int ImGuiCol.ScrollbarGrabHovered] <- Vector4 (0.407843142747879f, 0.407843142747879f, 0.407843142747879f, 1.0f) colors.[int ImGuiCol.ScrollbarGrabActive] <- Vector4 (0.5098039507865906f, 0.5098039507865906f, 0.5098039507865906f, 1.0f) colors.[int ImGuiCol.CheckMark] <- Vector4 (1.0f, 1.0f, 1.0f, 1.0f) - colors.[int ImGuiCol.SliderGrab] <- Vector4 (0.8784313797950745f, 0.8784313797950745f, 0.8784313797950745f, 1.0f) - colors.[int ImGuiCol.SliderGrabActive] <- Vector4 (0.9803921580314636f, 0.9803921580314636f, 0.9803921580314636f, 1.0f) + colors.[int ImGuiCol.SliderGrab] <- Vector4 (0.8784313797950745f, 0.8784313797950745f, 0.8784313797950745f, 0.3499999940395355f) + colors.[int ImGuiCol.SliderGrabActive] <- Vector4 (0.9803921580314636f, 0.9803921580314636f, 0.9803921580314636f, 0.3098039329051971f) colors.[int ImGuiCol.Button] <- Vector4 (0.2980392277240754f, 0.2980392277240754f, 0.2980392277240754f, 0.6015625f) colors.[int ImGuiCol.ButtonHovered] <- Vector4 (0.494117647409439f, 0.494117647409439f, 0.494117647409439f, 0.6015625f) colors.[int ImGuiCol.ButtonActive] <- Vector4 (0.658823549747467f, 0.658823549747467f, 0.658823549747467f, 0.6015625f) diff --git a/Nu/Nu/ImGui/ImGuiInterop.fs b/Nu/Nu/ImGui/ImGuiInterop.fs index b40137a838..f1694b820a 100644 --- a/Nu/Nu/ImGui/ImGuiInterop.fs +++ b/Nu/Nu/ImGui/ImGuiInterop.fs @@ -15,12 +15,27 @@ type Rect = [] module ImGuiInternal = + [] + extern void ImGui_ClearDragDrop () + + [] + extern void ImGui_ClearActiveID () + + [] + extern nativeint ImGui_GetDragDropPayload () + [] extern nativeint DockBuilder_GetCentralNode (uint32) [] extern void DockNode_GetRect (nativeint, nativeint) + /// Clear the drag drop action. + let tryCancelDragDrop () = + if ImGui_GetDragDropPayload () <> 0n then + ImGui_ClearActiveID () + ImGui_ClearDragDrop () + /// Try to get the bounds of the central dock node in the given dock space. let tryGetCentralDockNodeBounds dockSpaceId = let centralNode = DockBuilder_GetCentralNode dockSpaceId diff --git a/Nu/Nu/Metadata/HeightMap.fs b/Nu/Nu/Metadata/HeightMap.fs index 6124752bcc..ff5e9fdf1f 100644 --- a/Nu/Nu/Metadata/HeightMap.fs +++ b/Nu/Nu/Metadata/HeightMap.fs @@ -37,8 +37,8 @@ type [] HeightMap = | ImageHeightMap of Image AssetTag // only supports 8-bit depth on Red channel | RawHeightMap of RawHeightMap - static member private tryGetTextureData tryGetAssetFilePath (assetTag : Image AssetTag) = - match tryGetAssetFilePath assetTag with + static member private tryGetTextureData tryGetFilePath (assetTag : Image AssetTag) = + match tryGetFilePath assetTag with | Some filePath -> match OpenGL.Texture.TryCreateTextureData (false, filePath) with | Some textureData -> @@ -49,8 +49,8 @@ type [] HeightMap = | None -> ValueNone | None -> ValueNone - static member private tryGetRawAssetData tryGetAssetFilePath (assetTag : Raw AssetTag) = - match tryGetAssetFilePath assetTag with + static member private tryGetRawAssetData tryGetFilePath (assetTag : Raw AssetTag) = + match tryGetFilePath assetTag with | Some filePath -> try let bytes = File.ReadAllBytes filePath ValueSome bytes @@ -59,16 +59,16 @@ type [] HeightMap = ValueNone | None -> ValueNone - static member private tryGetImageHeightMapMetadata tryGetAssetFilePath (bounds : Box3) tiles image = + static member private tryGetImageHeightMapMetadata tryGetFilePath (bounds : Box3) tiles image = // attempt to load texture data - match HeightMap.tryGetTextureData tryGetAssetFilePath image with + match HeightMap.tryGetTextureData tryGetFilePath image with | ValueSome (metadata, compressed, bytes) -> // currently only supporting height data from block-compressed files if not compressed then - // compute normalize heights + // compute normalized heights let resolutionX = metadata.TextureWidth let resolutionY = metadata.TextureHeight let scalar = 1.0f / single Byte.MaxValue @@ -76,7 +76,7 @@ type [] HeightMap = [|for y in 0 .. dec resolutionY do for x in 0 .. dec resolutionX do let index = (resolutionX * y + x) * 4 + 2 // extract r channel of pixel - single bytes[index] * scalar|] + single bytes.[index] * scalar|] // compute positions and tex coordses let quadSizeX = bounds.Size.X / single (dec resolutionX) @@ -100,10 +100,10 @@ type [] HeightMap = else Log.info "Block-compressed image files are unsupported for use as height maps."; ValueNone | ValueNone -> ValueNone - static member private tryGetRawHeightMapMetadata tryGetAssetFilePath (bounds : Box3) tiles map = + static member private tryGetRawHeightMapMetadata tryGetFilePath (bounds : Box3) tiles map = // ensure raw asset exists - match HeightMap.tryGetRawAssetData tryGetAssetFilePath map.RawAsset with + match HeightMap.tryGetRawAssetData tryGetFilePath map.RawAsset with | ValueSome rawAsset -> try // read normalized heights @@ -168,7 +168,7 @@ type [] HeightMap = /// produced here is slightly different, with the border slightly clipped, and the terrain and quad size, slightly /// larger. i.e if the original map is 32m^2 and the original quad 1m^2 and the heightmap is 32x32, the quad axes /// below will be > 1.0. - static member tryGetMetadata (tryGetAssetFilePath : AssetTag -> string option) bounds tiles heightMap = + static member tryGetMetadata (tryGetFilePath : AssetTag -> string option) bounds tiles heightMap = match heightMap with - | ImageHeightMap image -> HeightMap.tryGetImageHeightMapMetadata tryGetAssetFilePath bounds tiles image - | RawHeightMap map -> HeightMap.tryGetRawHeightMapMetadata tryGetAssetFilePath bounds tiles map \ No newline at end of file + | ImageHeightMap image -> HeightMap.tryGetImageHeightMapMetadata tryGetFilePath bounds tiles image + | RawHeightMap map -> HeightMap.tryGetRawHeightMapMetadata tryGetFilePath bounds tiles map \ No newline at end of file diff --git a/Nu/Nu/OpenGL/OpenGL.SpriteBatch.fs b/Nu/Nu/OpenGL/OpenGL.SpriteBatch.fs index b1d8714754..676cc0c9b4 100644 --- a/Nu/Nu/OpenGL/OpenGL.SpriteBatch.fs +++ b/Nu/Nu/OpenGL/OpenGL.SpriteBatch.fs @@ -24,7 +24,7 @@ module SpriteBatch = | struct (ValueSome _, ValueNone) -> true | struct (ValueNone, ValueSome _) -> true | struct (ValueNone, ValueNone) -> false - | struct (ValueSome c, ValueSome c2) -> box2Neq c c2) || + | struct (ValueSome c, ValueSome c2) -> c <> c2) || state.BlendingFactorSrc <> state2.BlendingFactorSrc || state.BlendingFactorDst <> state2.BlendingFactorDst || state.BlendingEquation <> state2.BlendingEquation || diff --git a/Nu/Nu/OpenGL/OpenGL.Texture.fs b/Nu/Nu/OpenGL/OpenGL.Texture.fs index 08ee05212a..3c412fbfd0 100644 --- a/Nu/Nu/OpenGL/OpenGL.Texture.fs +++ b/Nu/Nu/OpenGL/OpenGL.Texture.fs @@ -41,7 +41,7 @@ module Texture = name.EndsWith "_f" || name.EndsWith "Filtered" - /// Infer the type of block compressionthat an asset with the given file path should utilize. + /// Infer the type of block compression that an asset with the given file path should utilize. let InferCompression (filePath : string) = let name = PathF.GetFileNameWithoutExtension filePath if name.EndsWith "_hm" || diff --git a/Nu/Nu/Particles/Particles.fs b/Nu/Nu/Particles/Particles.fs index 2d34097341..7bcb8e64f3 100644 --- a/Nu/Nu/Particles/Particles.fs +++ b/Nu/Nu/Particles/Particles.fs @@ -17,8 +17,9 @@ type [] Life = /// The progress made through the instance's life. static member getProgress (time : GameTime) life = - if life.LifeTimeOpt.NotZero - then single (time - life.StartTime) * life.ProgressScalar + if life.LifeTimeOpt.NotZero then + let deltaTime = time - life.StartTime + single (double deltaTime * double life.ProgressScalar) else 0.0f /// The progress made through the instance's life within a sub-range. @@ -38,7 +39,7 @@ type [] Life = static member make startTime lifeTimeOpt = { StartTime = startTime LifeTimeOpt = lifeTimeOpt - ProgressScalar = 1.0f / single lifeTimeOpt } + ProgressScalar = single (1.0 / double lifeTimeOpt) } /// A spatial constraint. type Constraint = @@ -198,7 +199,7 @@ module Transformer = /// Accelerate bodies both linearly and angularly. let accelerate (delta : GameTime) (bodies : Body SArray) = let mutable i = 0 - let scalar = single delta + let scalar = delta |> double |> single while i < bodies.Length do let body = &bodies.[i] body.Position <- body.Position + body.LinearVelocity * scalar @@ -207,7 +208,7 @@ module Transformer = /// Constrain bodies. let rec constrain (delta : GameTime) c (bodies : Body SArray) = - let scalar = single delta + let scalar = delta |> double |> single match c with | Sphere (radius, center) -> let mutable i = 0 @@ -246,7 +247,7 @@ module Transformer = fun delta _ c bodies -> match force with | Gravity gravity -> - let scalar = single delta + let scalar = delta |> double |> single let mutable i = 0 while i < bodies.Length do let body = &bodies.[i] @@ -254,7 +255,7 @@ module Transformer = i <- inc i Output.empty | Attractor (position, radius, force) -> - let scalar = single delta + let scalar = delta |> double |> single let mutable i = 0 while i < bodies.Length do let body = &bodies.[i] @@ -267,7 +268,7 @@ module Transformer = i <- inc i Output.empty | Drag (linearDrag, angularDrag) -> - let scalar = single delta + let scalar = delta |> double |> single let mutable i = 0 while i < bodies.Length do let body = &bodies.[i] @@ -781,8 +782,8 @@ type [] StaticSpriteEmitter<'a when 'a :> Particle and 'a : e // emit new particles if alive if Life.getAlive time emitter.Life then - let emitCount = single localTime * emitter.ParticleRate - let emitCountPrevious = single localTimePrevious * emitter.ParticleRate + let emitCount = double localTime * double emitter.ParticleRate + let emitCountPrevious = double localTimePrevious * double emitter.ParticleRate let emitCount = int emitCount - int emitCountPrevious for _ in 0 .. emitCount - 1 do StaticSpriteEmitter<'a>.emit time emitter @@ -908,7 +909,7 @@ module BasicStaticSpriteEmitter = let makeDefault time lifeTimeOpt particleLifeTimeMaxOpt particleRate particleMax = let image = asset Assets.Default.PackageName Assets.Default.ImageName let particleSeed = - { Life = Life.make GameTime.zero (GameTime.ofSeconds 2.0f) + { Life = Life.make GameTime.zero (GameTime.ofSeconds 2.0) Body = Body.defaultBody Offset = v3Zero Size = Constants.Engine.Particle2dSizeDefault @@ -1034,8 +1035,8 @@ type [] StaticBillboardEmitter<'a when 'a :> Particle and 'a // emit new particles if alive if Life.getAlive time emitter.Life then - let emitCount = single localTime * emitter.ParticleRate - let emitCountPrevious = single localTimePrevious * emitter.ParticleRate + let emitCount = double localTime * double emitter.ParticleRate + let emitCountPrevious = double localTimePrevious * double emitter.ParticleRate let emitCount = int emitCount - int emitCountPrevious for _ in 0 .. emitCount - 1 do StaticBillboardEmitter<'a>.emit time emitter @@ -1164,7 +1165,7 @@ module BasicStaticBillboardEmitter = /// Make the default basic billboard particle emitter. let makeDefault time lifeTimeOpt particleLifeTimeMaxOpt particleRate particleMax = let particleSeed = - { Life = Life.make GameTime.zero (GameTime.ofSeconds 2.0f) + { Life = Life.make GameTime.zero (GameTime.ofSeconds 2.0) Body = Body.defaultBody Offset = v3Zero Size = Constants.Engine.Particle3dSizeDefault diff --git a/Nu/Nu/Physics/AetherPhysicsEngine.fs b/Nu/Nu/Physics/AetherPhysicsEngine.fs index b21e863554..d99628179b 100644 --- a/Nu/Nu/Physics/AetherPhysicsEngine.fs +++ b/Nu/Nu/Physics/AetherPhysicsEngine.fs @@ -64,7 +64,9 @@ type private AetherFluidEmitter = { FluidEmitterDescriptor : FluidEmitterDescriptor2d States : AetherFluidParticleState array ActiveIndices : int HashSet - Grid : Dictionary } + Grid : Dictionary + Collisions : FluidCollision ConcurrentBag // OPTIMIZATION: cached to avoid large collections filling up the LOH. + } static let CellCapacityDefault = 20 @@ -255,9 +257,9 @@ type private AetherFluidEmitter = // apply gravity to velocity match state.Gravity with | GravityWorld -> state.VelocityUnscaled <- state.VelocityUnscaled + gravityLocal - | GravityIgnore -> () + | GravityOverride gravity -> state.VelocityUnscaled <- state.VelocityUnscaled + gravity.V2 * clockDelta * descriptor.ParticleScale | GravityScale scale -> state.VelocityUnscaled <- state.VelocityUnscaled + gravityLocal * scale - | Gravity gravity -> state.VelocityUnscaled <- state.VelocityUnscaled + gravity.V2 * clockDelta * descriptor.ParticleScale) + | GravityIgnore -> ()) // assert loop completion assert loopResult.IsCompleted @@ -446,6 +448,12 @@ type private AetherFluidEmitter = // assert loop completion assert loopResult.IsCompleted + // aggregate concurrent collisions to SArray + let collisionsArray = SArray.zeroCreate fluidEmitter.Collisions.Count + for i in 0 .. dec collisionsArray.Length do // OPTIMIZATION: using TryTake to avoid large array allocation which would happen for IEnumerators on ConcurrentBag + fluidEmitter.Collisions.TryTake &collisionsArray.[i] |> ignore + fluidEmitter.Collisions.Clear () + // relocate particles let outOfBoundsIndices = List 32 fluidEmitter.ActiveIndices.RemoveWhere (fun i -> @@ -454,11 +462,11 @@ type private AetherFluidEmitter = let state = &fluidEmitter.States.[i] state.VelocityUnscaled <- state.VelocityUnscaled + state.Delta state.PositionUnscaled <- state.PositionUnscaled + state.VelocityUnscaled + state.Delta - - ArrayPool.Shared.Return state.PotentialFixtureChildIndexes ArrayPool.Shared.Return state.PotentialFixtures + ArrayPool.Shared.Return state.PotentialFixtureChildIndexes ArrayPool.Shared.Return state.Neighbors + // remove when out of bounds, otherwise update cell let bounds = fluidEmitter.FluidEmitterDescriptor.SimulationBounds let removed = bounds.Contains state.PositionUnscaled = ContainmentType.Disjoint if removed then @@ -467,7 +475,7 @@ type private AetherFluidEmitter = cell.Remove i |> ignore if cell.Count = 0 then fluidEmitter.Grid.Remove state.CellId |> ignore else updateCell i fluidEmitter - removed) |> ignore + removed) |> ignore // aggregate state let particleStates = SArray.zeroCreate fluidEmitter.ActiveIndices.Count @@ -480,20 +488,23 @@ type private AetherFluidEmitter = let outOfBoundsParticles = SArray.zeroCreate outOfBoundsIndices.Count j <- 0 for i in outOfBoundsIndices do - outOfBoundsParticles.[j] <- fromFluid &fluidEmitter.States.[i] + let state = &fluidEmitter.States.[i] + outOfBoundsParticles.[j] <- fromFluid &state + state.Gravity <- Unchecked.defaultof<_> j <- inc j // fin - (particleStates, outOfBoundsParticles, collisions) + (particleStates, outOfBoundsParticles, collisionsArray) // nothing to do - else (SArray.empty, SArray.empty, ConcurrentBag ()) - + else (SArray.empty, SArray.empty, SArray.empty) + static member make descriptor = { FluidEmitterDescriptor = descriptor States = Array.zeroCreate descriptor.ParticlesMax ActiveIndices = HashSet (descriptor.ParticlesMax, HashIdentity.Structural) - Grid = Dictionary HashIdentity.Structural } + Grid = Dictionary HashIdentity.Structural + Collisions = ConcurrentBag () } /// The Aether interface of PhysicsEngineRenderContext. type AetherPhysicsEngineRenderContext = @@ -594,17 +605,20 @@ and [] AetherPhysicsEngine = Array.ofSeq contacts static member private configureBodyShapeProperties bodyProperties bodyShapePropertiesOpt (bodyShape : Fixture) = - // NOTE: temporary uint64 -> int conversions before we convert Aether to Box2D. + // NOTE: compared to Box2D.NET (Box2D v3), Aether.Physics2D (Box2D v2) only supports int16 instead of int for collision group, + // and int instead of uint64 for collision categories / mask. match bodyShapePropertiesOpt with | Some bodyShapeProperties -> bodyShape.Friction <- match bodyShapeProperties.FrictionOpt with Some f -> f | None -> bodyProperties.Friction bodyShape.Restitution <- match bodyShapeProperties.RestitutionOpt with Some r -> r | None -> bodyProperties.Restitution + bodyShape.CollisionGroup <- int16 <| match bodyShapeProperties.CollisionGroupOpt with Some cg -> cg | None -> bodyProperties.CollisionGroup bodyShape.CollisionCategories <- match bodyShapeProperties.CollisionCategoriesOpt with Some cc -> enum (int cc) | None -> enum (int bodyProperties.CollisionCategories) bodyShape.CollidesWith <- match bodyShapeProperties.CollisionMaskOpt with Some cm -> enum (int cm) | None -> enum (int bodyProperties.CollisionMask) bodyShape.IsSensor <- match bodyShapeProperties.SensorOpt with Some sensor -> sensor | None -> bodyProperties.Sensor | None -> bodyShape.Friction <- bodyProperties.Friction bodyShape.Restitution <- bodyProperties.Restitution + bodyShape.CollisionGroup <- int16 bodyProperties.CollisionGroup bodyShape.CollisionCategories <- enum (int bodyProperties.CollisionCategories) bodyShape.CollidesWith <- enum (int bodyProperties.CollisionMask) bodyShape.IsSensor <- bodyProperties.Sensor @@ -692,7 +706,7 @@ and [] AetherPhysicsEngine = static member private attachBoxRoundedShape bodySource (bodyProperties : BodyProperties) (boxRoundedShape : BoxRoundedShape) (body : Body) = let transform = Option.mapOrDefaultValue (fun (a : Affine) -> let mutable t = a in t.Matrix) m4Identity boxRoundedShape.TransformOpt - if quatNeq transform.Rotation quatIdentity then Log.warnOnce "BoxRoundedShape rotation not yet supported by AetherPhysicsEngine." // TODO: implement! + if transform.Rotation <> quatIdentity then Log.warnOnce "BoxRoundedShape rotation not yet supported by AetherPhysicsEngine." // TODO: implement! let width = AetherPhysicsEngine.toPhysicsPolygonDiameter (boxRoundedShape.Size.X * transform.Scale.X) let height = AetherPhysicsEngine.toPhysicsPolygonDiameter (boxRoundedShape.Size.Y * transform.Scale.Y) let radius = AetherPhysicsEngine.toPhysicsPolygonRadius (boxRoundedShape.Radius * transform.Scale.X) @@ -920,8 +934,7 @@ and [] AetherPhysicsEngine = static member private createBodyJointInternal bodyJointProperties bodyJointId physicsEngine = let resultOpt = match bodyJointProperties.BodyJoint with - | EmptyJoint -> - None + | EmptyJoint -> None | AetherBodyJoint bodyJoint -> let bodyId = bodyJointProperties.BodyJointTarget let body2Id = bodyJointProperties.BodyJointTarget2 @@ -930,9 +943,7 @@ and [] AetherPhysicsEngine = let joint = bodyJoint.CreateBodyJoint AetherPhysicsEngine.toPhysics AetherPhysicsEngine.toPhysicsV2 body body2 Some (joint, body, Some body2) | _ -> None - | _ -> - Log.warn ("Joint type '" + getCaseName bodyJointProperties.BodyJoint + "' not implemented for AetherPhysicsEngine.") - None + | _ -> Log.warn ("Joint type '" + getCaseName bodyJointProperties.BodyJoint + "' not implemented for AetherPhysicsEngine."); None match resultOpt with | Some (joint, body, body2Opt) -> joint.Tag <- bodyJointId @@ -1234,7 +1245,7 @@ and [] AetherPhysicsEngine = // manually sleep static bodies since aether won't sleep them itself if body.BodyType = Dynamics.BodyType.Static then body.Awake <- false - static member private applyGravity physicsStepAmount physicsEngine = + static member private stepGravity (physicsStepAmount : single) physicsEngine = for bodyEntry in physicsEngine.Bodies do let (gravity, body) = bodyEntry.Value if body.BodyType = Dynamics.BodyType.Dynamic then @@ -1345,7 +1356,6 @@ and [] AetherPhysicsEngine = | (false, _) -> 0.0f member physicsEngine.RayCast (ray, collisionCategory, collisionMask, closestOnly) = - ignore collisionCategory // not supported yet let results = List () let mutable fractionMin = Single.MaxValue let mutable closestOpt = None @@ -1353,7 +1363,8 @@ and [] AetherPhysicsEngine = RayCastReportFixtureDelegate (fun fixture point normal fraction -> match fixture.Tag with | :? BodyShapeIndex as bodyShapeIndex -> - if (int fixture.CollidesWith &&& int collisionMask) <> 0 then + if (int fixture.CollisionCategories &&& int collisionMask) <> 0 && + (int fixture.CollidesWith &&& int collisionCategory) <> 0 then let report = BodyIntersection.make bodyShapeIndex fraction (AetherPhysicsEngine.toPixelV3 point) (v3 normal.X normal.Y 0.0f) if fraction < fractionMin then fractionMin <- fraction @@ -1377,10 +1388,10 @@ and [] AetherPhysicsEngine = member physicsEngine.HandleMessage physicsMessage = AetherPhysicsEngine.handlePhysicsMessage physicsEngine physicsMessage - member physicsEngine.TryIntegrate stepTime = + member physicsEngine.TryIntegrate gameDelta = // constrain step time - let stepTime = stepTime.Seconds + let stepTime = gameDelta.SecondsF let stepTime = if stepTime > 0.0f && stepTime < 0.001f then 0.001f elif stepTime > 0.1f then 0.1f @@ -1388,7 +1399,7 @@ and [] AetherPhysicsEngine = // integrate only when time has passed if stepTime > 0.0f then - AetherPhysicsEngine.applyGravity stepTime physicsEngine + AetherPhysicsEngine.stepGravity stepTime physicsEngine physicsEngine.PhysicsContext.Step stepTime AetherPhysicsEngine.createIntegrationMessagesAndSleepAwakeStaticBodies physicsEngine let gravity = (physicsEngine :> PhysicsEngine).Gravity.V2 diff --git a/Nu/Nu/Physics/Box2dNetPhysicsEngine.fs b/Nu/Nu/Physics/Box2dNetPhysicsEngine.fs index 9395db064f..d3b88effd2 100644 --- a/Nu/Nu/Physics/Box2dNetPhysicsEngine.fs +++ b/Nu/Nu/Physics/Box2dNetPhysicsEngine.fs @@ -59,7 +59,9 @@ type private Box2dNetFluidEmitter = { FluidEmitterDescriptor : FluidEmitterDescriptor2d States : Box2dNetFluidParticleState array ActiveIndices : int HashSet - Grid : Dictionary } + Grid : Dictionary + Collisions : FluidCollision ConcurrentBag // OPTIMIZATION: cached to avoid large collections filling up the LOH. + } static let CellCapacityDefault = 20 @@ -248,9 +250,9 @@ type private Box2dNetFluidEmitter = // apply gravity to velocity match state.Gravity with | GravityWorld -> state.VelocityUnscaled <- state.VelocityUnscaled + gravityLocal - | GravityIgnore -> () + | GravityOverride gravity -> state.VelocityUnscaled <- state.VelocityUnscaled + gravity.V2 * clockDelta * descriptor.ParticleScale | GravityScale scale -> state.VelocityUnscaled <- state.VelocityUnscaled + gravityLocal * scale - | Gravity gravity -> state.VelocityUnscaled <- state.VelocityUnscaled + gravity.V2 * clockDelta * descriptor.ParticleScale) + | GravityIgnore -> ()) // assert loop completion assert loopResult.IsCompleted @@ -307,7 +309,6 @@ type private Box2dNetFluidEmitter = B2Worlds.b2World_OverlapAABB (context, aabb, queryFilter, query, 0n) |> ignore // parallel for 2 - resolve collisions - let collisions = ConcurrentBag () let loopResult = Parallel.ForEach (fluidEmitter.ActiveIndices, fun i -> // NOTE: collision testing must use physics engine units in calculations or the fluid collision in FluidSim page of @@ -444,8 +445,8 @@ type private Box2dNetFluidEmitter = // handle collision response if colliding then - collisions.Add - { FluidCollider = fromFluid &state + fluidEmitter.Collisions.Add + { FluidCollider = fromFluid &fluidEmitter.States.[i] FluidCollidee = B2Shapes.b2Shape_GetUserData shape :?> BodyShapeIndex Nearest = (toPixelV2 nearest).V3 Normal = (toPixelV2Normal normal).V3 } @@ -458,6 +459,12 @@ type private Box2dNetFluidEmitter = // assert loop completion assert loopResult.IsCompleted + // aggregate concurrent collisions to SArray + let collisionsArray = SArray.zeroCreate fluidEmitter.Collisions.Count + for i in 0 .. dec collisionsArray.Length do // OPTIMIZATION: using TryTake to avoid large array allocation which would happen for IEnumerators on ConcurrentBag + fluidEmitter.Collisions.TryTake &collisionsArray.[i] |> ignore + fluidEmitter.Collisions.Clear () + // relocate particles let outOfBoundsIndices = List 32 fluidEmitter.ActiveIndices.RemoveWhere (fun i -> @@ -477,7 +484,6 @@ type private Box2dNetFluidEmitter = let cell = fluidEmitter.Grid.[state.CellId] cell.Remove i |> ignore if cell.Count = 0 then fluidEmitter.Grid.Remove state.CellId |> ignore - state.Gravity <- Unchecked.defaultof<_> else updateCell i fluidEmitter removed) |> ignore @@ -492,20 +498,27 @@ type private Box2dNetFluidEmitter = let outOfBoundsParticles = SArray.zeroCreate outOfBoundsIndices.Count j <- 0 for i in outOfBoundsIndices do - outOfBoundsParticles.[j] <- fromFluid &fluidEmitter.States.[i] + let state = &fluidEmitter.States.[i] + outOfBoundsParticles.[j] <- fromFluid &state + state.Gravity <- Unchecked.defaultof<_> j <- inc j // fin - (particleStates, outOfBoundsParticles, collisions) + (particleStates, outOfBoundsParticles, collisionsArray) // nothing to do - else (SArray.empty, SArray.empty, ConcurrentBag ()) + else (SArray.empty, SArray.empty, SArray.empty) static member make descriptor = { FluidEmitterDescriptor = descriptor States = Array.zeroCreate descriptor.ParticlesMax ActiveIndices = HashSet (descriptor.ParticlesMax, HashIdentity.Structural) - Grid = Dictionary HashIdentity.Structural } + Grid = Dictionary HashIdentity.Structural + Collisions = ConcurrentBag () } + +type private Box2dNetPhysicsEngineContactsTracker = + { NewContacts : ConcurrentDictionary + ExistingContacts : HashSet } /// The Box2D.NET interface of PhysicsEngineRenderContext. type Box2dNetPhysicsEngineRenderContext = @@ -515,7 +528,7 @@ type Box2dNetPhysicsEngineRenderContext = abstract DrawCircle : position : Vector2 * radius : single * color : Color -> unit /// The Box2D.NET implementation of PhysicsEngine. -and [] Box2dNetPhysicsEngine = +type [] Box2dNetPhysicsEngine = private { mutable PhysicsContextId : B2WorldId Bodies : Dictionary @@ -524,7 +537,8 @@ and [] Box2dNetPhysicsEngine = BreakableJoints : Dictionary CreateBodyJointMessages : Dictionary FluidEmitters : Dictionary - IntegrationMessages : IntegrationMessage List } + IntegrationMessages : IntegrationMessage List // OPTIMIZATION: cached to avoid large arrays filling up the LOH. + ContactsTracker : Box2dNetPhysicsEngineContactsTracker } // NOTE: supports thread safety for b2PreSolveFcn. member private this.PhysicsContext = B2Worlds.b2GetWorld (int this.PhysicsContextId.index1) @@ -684,8 +698,9 @@ and [] Box2dNetPhysicsEngine = bodyShapeDef.filter.categoryBits <- bodyProperties.CollisionCategories bodyShapeDef.filter.maskBits <- bodyProperties.CollisionMask bodyShapeDef.isSensor <- bodyProperties.Sensor - bodyShapeDef.enableContactEvents <- true // record non-sensor contacts for b2World_GetContactEvents - bodyShapeDef.enableSensorEvents <- true // record sensor contacts for b2World_GetSensorEvents + bodyShapeDef.enablePreSolveEvents <- Constants.Physics.Collision2dFrameCompensation // record non-sensor begin contact events via preSolveCallback only when needed + bodyShapeDef.enableContactEvents <- true // record non-sensor contacts via b2World_GetContactEvents + bodyShapeDef.enableSensorEvents <- true // record sensor contacts via b2World_GetSensorEvents bodyShapeDef.userData <- { BodyId = { BodySource = bodySource; BodyIndex = bodyProperties.BodyIndex } BodyShapeIndex = match bodyShapePropertiesOpt with Some p -> p.BodyShapeIndex | None -> 0 } @@ -999,9 +1014,9 @@ and [] Box2dNetPhysicsEngine = if bodyDef.``type`` = B2BodyType.b2_dynamicBody then match bodyProperties.Gravity with | GravityWorld -> bodyDef.gravityScale <- 1.0f; ValueNone - | GravityIgnore -> bodyDef.gravityScale <- 0.0f; ValueNone + | GravityOverride gravity -> bodyDef.gravityScale <- 0.0f; ValueSome gravity // NOTE: gravity overrides are handled by applying a manual force each step. | GravityScale scale -> bodyDef.gravityScale <- scale; ValueNone - | Gravity gravity -> bodyDef.gravityScale <- 0.0f; ValueSome gravity // NOTE: gravity overrides are handled by applying a manual force each step. + | GravityIgnore -> bodyDef.gravityScale <- 0.0f; ValueNone else ValueNone bodyDef.isBullet <- match bodyProperties.CollisionDetection with Continuous -> true | Discrete -> false bodyDef.isAwake <- bodyProperties.Awake @@ -1069,8 +1084,7 @@ and [] Box2dNetPhysicsEngine = static member private createBodyJointInternal bodyJointProperties bodyJointId physicsEngine = if bodyJointProperties.BodyJointEnabled && not bodyJointProperties.Broken then match bodyJointProperties.BodyJoint with - | EmptyJoint -> - () + | EmptyJoint -> () | Box2dNetBodyJoint bodyJoint -> let bodyId = bodyJointProperties.BodyJointTarget let body2Id = bodyJointProperties.BodyJointTarget2 @@ -1088,8 +1102,7 @@ and [] Box2dNetPhysicsEngine = | None -> () else Log.warn ("Could not add body joint for '" + scstring bodyJointId + "' as it already exists.") | _ -> () - | _ -> - Log.warn ("Joint type '" + getCaseName bodyJointProperties.BodyJoint + "' not implemented for Box2dNetPhysicsEngine.") + | _ -> Log.warn ("Joint type '" + getCaseName bodyJointProperties.BodyJoint + "' not implemented for Box2dNetPhysicsEngine.") static member private createBodyJoint (createBodyJointMessage : CreateBodyJointMessage) physicsEngine = @@ -1188,6 +1201,8 @@ and [] Box2dNetPhysicsEngine = | B2JointType.b2_revoluteJoint -> B2RevoluteJoints.b2RevoluteJoint_EnableMotor (joint, setBodyJointMotorEnabledMessage.MotorEnabled) | B2JointType.b2_wheelJoint -> B2WheelJoints.b2WheelJoint_EnableMotor (joint, setBodyJointMotorEnabledMessage.MotorEnabled) | _ -> () + if setBodyJointMotorEnabledMessage.MotorEnabled then + B2Joints.b2Joint_WakeBodies joint | (false, _) -> () static member private setBodyJointMotorSpeed (setBodyJointMotorSpeedMessage : SetBodyJointMotorSpeedMessage) physicsEngine = @@ -1199,14 +1214,18 @@ and [] Box2dNetPhysicsEngine = | B2JointType.b2_revoluteJoint -> B2RevoluteJoints.b2RevoluteJoint_SetMotorSpeed (joint, setBodyJointMotorSpeedMessage.MotorSpeed) | B2JointType.b2_wheelJoint -> B2WheelJoints.b2WheelJoint_SetMotorSpeed (joint, setBodyJointMotorSpeedMessage.MotorSpeed) | _ -> () + if setBodyJointMotorSpeedMessage.MotorSpeed <> 0.0f then + B2Joints.b2Joint_WakeBodies joint | (false, _) -> () static member private setBodyJointTargetAngle (setBodyJointTargetAngleMessage : SetBodyJointTargetAngleMessage) physicsEngine = match physicsEngine.Joints.TryGetValue setBodyJointTargetAngleMessage.BodyJointId with | (true, joint) -> match B2Joints.b2Joint_GetType joint with - | B2JointType.b2_revoluteJoint -> B2RevoluteJoints.b2RevoluteJoint_SetTargetAngle (joint, setBodyJointTargetAngleMessage.TargetAngle) + | B2JointType.b2_revoluteJoint -> + B2RevoluteJoints.b2RevoluteJoint_SetTargetAngle (joint, setBodyJointTargetAngleMessage.TargetAngle) | _ -> () + B2Joints.b2Joint_WakeBodies joint | (false, _) -> () static member private applyBodyLinearImpulse (applyBodyLinearImpulseMessage : ApplyBodyLinearImpulseMessage) physicsEngine = @@ -1401,22 +1420,112 @@ and [] Box2dNetPhysicsEngine = | ClearFluidParticlesMessage id -> Box2dNetPhysicsEngine.clearFluidParticlesMessage id physicsEngine | SetGravityMessage gravity -> Box2dNetPhysicsEngine.setGravityMessage gravity physicsEngine - static member makePhysicsContext gravity = + // NOTE: from Box2D documentation https://box2d.org/documentation/md_simulation.html + // update transforms - "Note that continuous collision does not generate events. Instead they are generated the next time step. However, continuous collision will issue a b2PreSolveFcn callback." + // we want penetration messages to be recorded on the same time step as penetration instead of the next, so we record it in the b2PreSolveFcn callback. + static let preSolveCallback = + b2PreSolveFcn (fun shapeIdA shapeIdB manifold context -> // can be called from multiple threads at once - write to concurrent collections only + let contactsTracker = context :?> Box2dNetPhysicsEngineContactsTracker + if not (contactsTracker.ExistingContacts.Contains (shapeIdA, shapeIdB)) then + let bodyShapeA = B2Shapes.b2Shape_GetUserData shapeIdA :?> BodyShapeIndex + let bodyShapeB = B2Shapes.b2Shape_GetUserData shapeIdB :?> BodyShapeIndex + let normal = Vector3 (manifold.normal.X, manifold.normal.Y, 0.0f) + contactsTracker.NewContacts.TryAdd + (struct (shapeIdA, shapeIdB), + { BodyShapeSource = bodyShapeA; BodyShapeTarget = bodyShapeB; Normal = normal }) + |> ignore + true) + + static member private makePhysicsContext gravity contactsTracker = let mutable worldDef = B2Types.b2DefaultWorldDef () worldDef.gravity <- gravity - B2Worlds.b2CreateWorld &worldDef + let world = B2Worlds.b2CreateWorld &worldDef + B2Worlds.b2World_SetPreSolveCallback (world, preSolveCallback, (contactsTracker : Box2dNetPhysicsEngineContactsTracker)) + world /// Make a physics engine. static member make gravity = - { PhysicsContextId = Box2dNetPhysicsEngine.makePhysicsContext (Box2dNetPhysicsEngine.toPhysicsV2 gravity) + let contactsTracker = + { NewContacts = ConcurrentDictionary () + ExistingContacts = HashSet () } + { PhysicsContextId = Box2dNetPhysicsEngine.makePhysicsContext (Box2dNetPhysicsEngine.toPhysicsV2 gravity) contactsTracker Bodies = Dictionary HashIdentity.Structural BodyGravityOverrides = Dictionary HashIdentity.Structural Joints = Dictionary HashIdentity.Structural BreakableJoints = Dictionary HashIdentity.Structural CreateBodyJointMessages = Dictionary HashIdentity.Structural FluidEmitters = Dictionary HashIdentity.Structural + ContactsTracker = contactsTracker IntegrationMessages = List () } :> PhysicsEngine + static let renderCallback = + b2OverlapResultFcn (fun shape context -> + let renderContext = context :?> Box2dNetPhysicsEngineRenderContext + + // get body and transform + let body = B2Shapes.b2Shape_GetBody shape + let mutable transform = B2Bodies.b2Body_GetTransform body + + // compute color consistent with JoltSharp which defaults to MotionTypeColor: https://github.com/amerkoleci/JoltPhysicsSharp/blob/fbc0511c987043a16b6f985ae00633285ee56cb9/src/JoltPhysicsSharp/DrawSettings.cs#L33 + // which is defined here: https://github.com/amerkoleci/JoltPhysicsSharp/blob/fbc0511c987043a16b6f985ae00633285ee56cb9/src/JoltPhysicsSharp/ShapeColor.cs#L20 + let color = + match B2Bodies.b2Body_GetType body with + | B2BodyType.b2_dynamicBody -> // dynamic = random color per instance + (B2Bodies.b2Body_GetUserData body).GetHashCode () |> uint |> colorPacked |> _.WithA(1f) // use the Nu BodyIndex because physics engine bodies are recreated on property assignment + | B2BodyType.b2_kinematicBody -> // keyframed + Color.Green + | _ -> // static or anything else + Color.Gray + + // render shape + match B2Shapes.b2Shape_GetType shape with + | B2ShapeType.b2_circleShape -> + let circle = B2Shapes.b2Shape_GetCircle shape + let position = B2MathFunction.b2TransformPoint (&transform, circle.center) |> Box2dNetPhysicsEngine.toPixelV2 + let radius = Box2dNetPhysicsEngine.toPixel circle.radius + renderContext.DrawCircle (position, radius, color) + | B2ShapeType.b2_capsuleShape -> + let capsule = B2Shapes.b2Shape_GetCapsule shape + let center1 = B2MathFunction.b2TransformPoint (&transform, capsule.center1) |> Box2dNetPhysicsEngine.toPixelV2 + let center2 = B2MathFunction.b2TransformPoint (&transform, capsule.center2) |> Box2dNetPhysicsEngine.toPixelV2 + let radius = Box2dNetPhysicsEngine.toPixel capsule.radius + let direction = center2 - center1 + let perpendicular = Vector2(-direction.Y, direction.X).Normalized * radius + renderContext.DrawCircle (center1, radius, color) + renderContext.DrawCircle (center2, radius, color) + renderContext.DrawLine (center1 + perpendicular, center2 + perpendicular, color) + renderContext.DrawLine (center1 - perpendicular, center2 - perpendicular, color) + | B2ShapeType.b2_segmentShape -> + let segment = B2Shapes.b2Shape_GetSegment shape + let start = B2MathFunction.b2TransformPoint (&transform, segment.point1) |> Box2dNetPhysicsEngine.toPixelV2 + let stop = B2MathFunction.b2TransformPoint (&transform, segment.point2) |> Box2dNetPhysicsEngine.toPixelV2 + renderContext.DrawLine (start, stop, color) + | B2ShapeType.b2_polygonShape -> + let polygon = B2Shapes.b2Shape_GetPolygon shape + if polygon.radius = 0.0f then + for i in 0 .. dec polygon.count do + let start = B2MathFunction.b2TransformPoint (&transform, polygon.vertices.[i]) |> Box2dNetPhysicsEngine.toPixelV2 + let stop = B2MathFunction.b2TransformPoint (&transform, polygon.vertices.[if i < dec polygon.count then inc i else 0]) |> Box2dNetPhysicsEngine.toPixelV2 + renderContext.DrawLine (start, stop, color) + else + let radius = Box2dNetPhysicsEngine.toPixel polygon.radius + for i in 0 .. dec polygon.count do + let start = B2MathFunction.b2TransformPoint (&transform, polygon.vertices.[i]) |> Box2dNetPhysicsEngine.toPixelV2 + let stop = B2MathFunction.b2TransformPoint (&transform, polygon.vertices.[if i < dec polygon.count then inc i else 0]) |> Box2dNetPhysicsEngine.toPixelV2 + let perpendicular = B2MathFunction.b2RotateVector (transform.q, polygon.normals[i]) * radius + let perpendicular = v2 perpendicular.X perpendicular.Y + renderContext.DrawCircle (start, radius, color) + renderContext.DrawLine (start + perpendicular, stop + perpendicular, color) + | B2ShapeType.b2_chainSegmentShape -> + let segment = (B2Shapes.b2Shape_GetChainSegment shape).segment + let start = B2MathFunction.b2TransformPoint (&transform, segment.point1) |> Box2dNetPhysicsEngine.toPixelV2 + let stop = B2MathFunction.b2TransformPoint (&transform, segment.point2) |> Box2dNetPhysicsEngine.toPixelV2 + renderContext.DrawLine (start, stop, color) + | _ -> () + + // continue querying + true) + interface PhysicsEngine with member physicsEngine.GravityDefault = @@ -1553,10 +1662,10 @@ and [] Box2dNetPhysicsEngine = member physicsEngine.HandleMessage physicsMessage = Box2dNetPhysicsEngine.handlePhysicsMessage physicsEngine physicsMessage - member physicsEngine.TryIntegrate stepTime = + member physicsEngine.TryIntegrate gameDelta = // constrain step time - let stepTime = stepTime.Seconds + let stepTime = gameDelta.SecondsF let stepTime = if stepTime > 0.0f && stepTime < 0.001f then 0.001f elif stepTime > 0.1f then 0.1f @@ -1570,7 +1679,7 @@ and [] Box2dNetPhysicsEngine = let body = physicsEngine.Bodies.[bodyId] if B2Bodies.b2Body_IsAwake body then let gravity = Box2dNetPhysicsEngine.toPhysicsV2 gravityOverride - B2Bodies.b2Body_SetLinearVelocity (body, B2Bodies.b2Body_GetLinearVelocity body + gravity * stepTime) + B2Bodies.b2Body_SetLinearVelocity (body, B2Bodies.b2Body_GetLinearVelocity body + gravity * stepTime) // NOTE: wakes body when awake not checked. // step the world B2Worlds.b2World_Step (physicsEngine.PhysicsContextId, stepTime, Constants.Physics.Collision2dSteps) @@ -1600,19 +1709,32 @@ and [] Box2dNetPhysicsEngine = LinearVelocity = Box2dNetPhysicsEngine.toPixelV3 (B2Bodies.b2Body_GetLinearVelocity transform.bodyId) AngularVelocity = v3 0.0f 0.0f (B2Bodies.b2Body_GetAngularVelocity transform.bodyId) }) - // collect penetrations for non-sensors + // collect penetrations let contacts = B2Worlds.b2World_GetContactEvents physicsEngine.PhysicsContextId - for i in 0 .. dec contacts.beginCount do - let penetration = &contacts.beginEvents.[i] // NOTE: from Box2D documentation, rollingImpulse is always zero. - let bodyShapeA = B2Shapes.b2Shape_GetUserData penetration.shapeIdA :?> BodyShapeIndex - let bodyShapeB = B2Shapes.b2Shape_GetUserData penetration.shapeIdB :?> BodyShapeIndex - let normal = Vector3 (penetration.manifold.normal.X, penetration.manifold.normal.Y, 0.0f) - physicsEngine.IntegrationMessages.Add (BodyPenetrationMessage { BodyShapeSource = bodyShapeA; BodyShapeTarget = bodyShapeB; Normal = normal }) - physicsEngine.IntegrationMessages.Add (BodyPenetrationMessage { BodyShapeSource = bodyShapeB; BodyShapeTarget = bodyShapeA; Normal = -normal }) + if Constants.Physics.Collision2dFrameCompensation then + + // collect penetrations for non-sensors from preSolveCallback which is called on same time step as penetration unlike contact events which exist one step later + for KeyValue (shapeIds, penetration) in physicsEngine.ContactsTracker.NewContacts do + physicsEngine.IntegrationMessages.Add (BodyPenetrationMessage { BodyShapeSource = penetration.BodyShapeSource; BodyShapeTarget = penetration.BodyShapeTarget; Normal = penetration.Normal }) + physicsEngine.IntegrationMessages.Add (BodyPenetrationMessage { BodyShapeSource = penetration.BodyShapeTarget; BodyShapeTarget = penetration.BodyShapeSource; Normal = -penetration.Normal }) + physicsEngine.ContactsTracker.ExistingContacts.Add shapeIds |> ignore + physicsEngine.ContactsTracker.NewContacts.Clear () + + else + + // collect penetrations for non-sensors from begin contact events, which are performant but one time step late compared to the actual penetration + for i in 0 .. dec contacts.beginCount do + let penetration = &contacts.beginEvents.[i] + let bodyShapeA = B2Shapes.b2Shape_GetUserData penetration.shapeIdA :?> BodyShapeIndex + let bodyShapeB = B2Shapes.b2Shape_GetUserData penetration.shapeIdB :?> BodyShapeIndex + let normal = v3 penetration.manifold.normal.X penetration.manifold.normal.Y 0.0f + physicsEngine.IntegrationMessages.Add (BodyPenetrationMessage { BodyShapeSource = bodyShapeA; BodyShapeTarget = bodyShapeB; Normal = normal }) + physicsEngine.IntegrationMessages.Add (BodyPenetrationMessage { BodyShapeSource = bodyShapeB; BodyShapeTarget = bodyShapeA; Normal = -normal }) // collect separations for non-sensors for i in 0 .. dec contacts.endCount do let separation = &contacts.endEvents.[i] + physicsEngine.ContactsTracker.ExistingContacts.Remove (separation.shapeIdA, separation.shapeIdB) |> ignore let bodyShapeA = B2Shapes.b2Shape_GetUserData separation.shapeIdA :?> BodyShapeIndex let bodyShapeB = B2Shapes.b2Shape_GetUserData separation.shapeIdB :?> BodyShapeIndex physicsEngine.IntegrationMessages.Add (BodySeparationMessage { BodyShapeSource = bodyShapeA; BodyShapeTarget = bodyShapeB }) @@ -1665,79 +1787,13 @@ and [] Box2dNetPhysicsEngine = let eyeBounds = renderContext.EyeBounds let v2ToB2Vec2 (v : Vector2) = B2Vec2 (Box2dNetPhysicsEngine.toPhysics v.X, Box2dNetPhysicsEngine.toPhysics v.Y) let eyeAabb = B2AABB (v2ToB2Vec2 eyeBounds.Min, v2ToB2Vec2 eyeBounds.Max) - let callback = - b2OverlapResultFcn (fun shape _ -> - - // get body and transform - let body = B2Shapes.b2Shape_GetBody shape - let mutable transform = B2Bodies.b2Body_GetTransform body - - // compute color consistent with JoltSharp which defaults to MotionTypeColor: https://github.com/amerkoleci/JoltPhysicsSharp/blob/fbc0511c987043a16b6f985ae00633285ee56cb9/src/JoltPhysicsSharp/DrawSettings.cs#L33 - // which is defined here: https://github.com/amerkoleci/JoltPhysicsSharp/blob/fbc0511c987043a16b6f985ae00633285ee56cb9/src/JoltPhysicsSharp/ShapeColor.cs#L20 - let color = - match B2Bodies.b2Body_GetType body with - | B2BodyType.b2_dynamicBody -> // dynamic = random color per instance - (B2Bodies.b2Body_GetUserData body).GetHashCode () |> uint |> colorPacked |> _.WithA(1f) // use the Nu BodyIndex because physics engine bodies are recreated on property assignment - | B2BodyType.b2_kinematicBody -> // keyframed - Color.Green - | _ -> // static or anything else - Color.Gray - - // render shape - match B2Shapes.b2Shape_GetType shape with - | B2ShapeType.b2_circleShape -> - let circle = B2Shapes.b2Shape_GetCircle shape - let position = B2MathFunction.b2TransformPoint (&transform, circle.center) |> Box2dNetPhysicsEngine.toPixelV2 - let radius = Box2dNetPhysicsEngine.toPixel circle.radius - renderContext.DrawCircle (position, radius, color) - | B2ShapeType.b2_capsuleShape -> - let capsule = B2Shapes.b2Shape_GetCapsule shape - let center1 = B2MathFunction.b2TransformPoint (&transform, capsule.center1) |> Box2dNetPhysicsEngine.toPixelV2 - let center2 = B2MathFunction.b2TransformPoint (&transform, capsule.center2) |> Box2dNetPhysicsEngine.toPixelV2 - let radius = Box2dNetPhysicsEngine.toPixel capsule.radius - let direction = center2 - center1 - let perpendicular = Vector2(-direction.Y, direction.X).Normalized * radius - renderContext.DrawCircle (center1, radius, color) - renderContext.DrawCircle (center2, radius, color) - renderContext.DrawLine (center1 + perpendicular, center2 + perpendicular, color) - renderContext.DrawLine (center1 - perpendicular, center2 - perpendicular, color) - | B2ShapeType.b2_segmentShape -> - let segment = B2Shapes.b2Shape_GetSegment shape - let start = B2MathFunction.b2TransformPoint (&transform, segment.point1) |> Box2dNetPhysicsEngine.toPixelV2 - let stop = B2MathFunction.b2TransformPoint (&transform, segment.point2) |> Box2dNetPhysicsEngine.toPixelV2 - renderContext.DrawLine (start, stop, color) - | B2ShapeType.b2_polygonShape -> - let polygon = B2Shapes.b2Shape_GetPolygon shape - if polygon.radius = 0.0f then - for i in 0 .. dec polygon.count do - let start = B2MathFunction.b2TransformPoint (&transform, polygon.vertices.[i]) |> Box2dNetPhysicsEngine.toPixelV2 - let stop = B2MathFunction.b2TransformPoint (&transform, polygon.vertices.[if i < dec polygon.count then inc i else 0]) |> Box2dNetPhysicsEngine.toPixelV2 - renderContext.DrawLine (start, stop, color) - else - let radius = Box2dNetPhysicsEngine.toPixel polygon.radius - for i in 0 .. dec polygon.count do - let start = B2MathFunction.b2TransformPoint (&transform, polygon.vertices.[i]) |> Box2dNetPhysicsEngine.toPixelV2 - let stop = B2MathFunction.b2TransformPoint (&transform, polygon.vertices.[if i < dec polygon.count then inc i else 0]) |> Box2dNetPhysicsEngine.toPixelV2 - let perpendicular = B2MathFunction.b2RotateVector (transform.q, polygon.normals[i]) * radius - let perpendicular = v2 perpendicular.X perpendicular.Y - renderContext.DrawCircle (start, radius, color) - renderContext.DrawLine (start + perpendicular, stop + perpendicular, color) - | B2ShapeType.b2_chainSegmentShape -> - let segment = (B2Shapes.b2Shape_GetChainSegment shape).segment - let start = B2MathFunction.b2TransformPoint (&transform, segment.point1) |> Box2dNetPhysicsEngine.toPixelV2 - let stop = B2MathFunction.b2TransformPoint (&transform, segment.point2) |> Box2dNetPhysicsEngine.toPixelV2 - renderContext.DrawLine (start, stop, color) - | _ -> () - - // continue querying - true) B2Worlds.b2World_OverlapAABB (physicsEngine.PhysicsContextId, eyeAabb, B2QueryFilter (UInt64.MaxValue, UInt64.MaxValue), - callback, - null) |> ignore + renderCallback, + (renderContext : Box2dNetPhysicsEngineRenderContext)) |> ignore | _ -> () @@ -1749,7 +1805,7 @@ and [] Box2dNetPhysicsEngine = physicsEngine.BodyGravityOverrides.Clear () physicsEngine.CreateBodyJointMessages.Clear () let oldContext = physicsEngine.PhysicsContextId - physicsEngine.PhysicsContextId <- Box2dNetPhysicsEngine.makePhysicsContext (B2Worlds.b2World_GetGravity oldContext) + physicsEngine.PhysicsContextId <- Box2dNetPhysicsEngine.makePhysicsContext (B2Worlds.b2World_GetGravity oldContext) physicsEngine.ContactsTracker B2Worlds.b2DestroyWorld oldContext member physicsEngine.CleanUp () = diff --git a/Nu/Nu/Physics/JoltPhysicsEngine.fs b/Nu/Nu/Physics/JoltPhysicsEngine.fs index 6dcb3ffbee..8d7836b98b 100644 --- a/Nu/Nu/Physics/JoltPhysicsEngine.fs +++ b/Nu/Nu/Physics/JoltPhysicsEngine.fs @@ -595,12 +595,11 @@ and [] JoltPhysicsEngine = bodyCreationSettings.GravityFactor <- match bodyProperties.Gravity with | GravityWorld -> 1.0f - | GravityIgnore -> 0.0f - | GravityScale scale -> scale - | Gravity gravity -> - // NOTE: this needs manual bookkeeping like for characters. - Log.warnOnce "Individual gravity configuration is unsupported for non-characters in JoltPhysicsEngine; interpreting as a scale by magnitude instead." + | GravityOverride gravity -> + Log.warnOnce "Gravity override is unsupported in JoltPhysicsEngine; interpreting as a scale by magnitude instead." gravity.Magnitude + | GravityScale scale -> scale + | GravityIgnore -> 0.0f bodyCreationSettings.MotionQuality <- match bodyProperties.CollisionDetection with | Discrete -> MotionQuality.Discrete @@ -1481,13 +1480,14 @@ and [] JoltPhysicsEngine = member physicsEngine.HandleMessage physicsMessage = JoltPhysicsEngine.handlePhysicsMessage physicsEngine physicsMessage - member physicsEngine.TryIntegrate stepTime = + member physicsEngine.TryIntegrate gameDelta = // integrate only when time has passed - if not stepTime.IsZero then + let stepTime = gameDelta.SecondsF + if stepTime > 0.0f then // update non-character physics, logging on error (integration should still advance sim regardless of error) - match physicsEngine.PhysicsContext.Update (stepTime.Seconds, Constants.Physics.Collision3dSteps, physicsEngine.JobSystem) with + match physicsEngine.PhysicsContext.Update (stepTime, Constants.Physics.Collision3dSteps, physicsEngine.JobSystem) with | PhysicsUpdateError.ManifoldCacheFull as error -> Log.warnOnce ("Jolt Physics internal error: " + scstring error + ". Consider increasing Constants.Physics." + @@ -1506,7 +1506,14 @@ and [] JoltPhysicsEngine = let characterLayer = Constants.Physics.ObjectLayerMoving for character in physicsEngine.Characters.Values do let characterUserData = physicsEngine.CharacterUserData.[character.ID] - let characterGravity = Gravity.localize physicsEngine.PhysicsContext.Gravity characterUserData.CharacterGravity + let characterGravityFactor = + match characterUserData.CharacterGravity with + | GravityWorld -> 1.0f + | GravityOverride gravity -> + Log.warnOnce "Gravity override is unsupported in JoltPhysicsEngine; interpreting as a scale by magnitude instead." + gravity.Magnitude + | GravityScale scale -> scale + | GravityIgnore -> 0.0f let characterProperties = characterUserData.CharacterProperties let mutable characterUpdateSettings = ExtendedUpdateSettings @@ -1517,10 +1524,14 @@ and [] JoltPhysicsEngine = WalkStairsMinStepForward = characterProperties.StairStepForwardMin, WalkStairsCosAngleForwardContact = characterProperties.StairCosAngleForwardContact) character.LinearVelocity <- - if character.GroundState = GroundState.OnGround - then character.LinearVelocity.MapY (max 0.0f) - else character.LinearVelocity + characterGravity * stepTime.Seconds - character.ExtendedUpdate (stepTime.Seconds, characterUpdateSettings, &characterLayer, physicsEngine.PhysicsContext) + if character.GroundState = GroundState.OnGround then + if characterGravityFactor < 0.0f + then character.LinearVelocity.MapY (min 0.0f) + else character.LinearVelocity.MapY (max 0.0f) + else + let characterGravity = physicsEngine.PhysicsContext.Gravity * characterGravityFactor + character.LinearVelocity + characterGravity * stepTime + character.ExtendedUpdate (stepTime, characterUpdateSettings, &characterLayer, physicsEngine.PhysicsContext) // update constraints for bodyConstraintEntry in physicsEngine.BodyConstraintBreakingPoints do diff --git a/Nu/Nu/Physics/PhysicsEngine.fs b/Nu/Nu/Physics/PhysicsEngine.fs index 3ecd735130..0721a1e8cd 100644 --- a/Nu/Nu/Physics/PhysicsEngine.fs +++ b/Nu/Nu/Physics/PhysicsEngine.fs @@ -176,7 +176,7 @@ type FluidEmitterMessage = { FluidEmitterId : FluidEmitterId FluidParticles : FluidParticle SArray OutOfBoundsParticles : FluidParticle SArray - FluidCollisions : FluidCollision ConcurrentBag } + FluidCollisions : FluidCollision SArray } /// A message to the physics system to update the description of a fluid emitter. type UpdateFluidEmitterMessage = @@ -310,7 +310,7 @@ type PhysicsEngine = abstract HandleMessage : message : PhysicsMessage -> unit /// Attempt to integrate the physics system one step. - abstract TryIntegrate : delta : GameTime -> IntegrationMessage SArray option + abstract TryIntegrate : gameDelta : GameTime -> IntegrationMessage SArray option /// Attempt to render physics with the given physics-engine-specific render context. abstract TryRender : renderContext : PhysicsEngineRenderContext -> unit diff --git a/Nu/Nu/Physics/PhysicsPrelude.fs b/Nu/Nu/Physics/PhysicsPrelude.fs index 960061f814..dad7139835 100644 --- a/Nu/Nu/Physics/PhysicsPrelude.fs +++ b/Nu/Nu/Physics/PhysicsPrelude.fs @@ -412,21 +412,21 @@ type VehicleProperties = | VehiclePropertiesAbsent | VehiclePropertiesBox2D | VehiclePropertiesJolt of JoltPhysicsSharp.VehicleConstraintSettings - -/// Describes whether a body should follow a scale of world gravity (Default = 1, None = 0) or use an override. + +/// Describes the gravitational property of a body. type Gravity = | GravityWorld - | GravityIgnore + | GravityOverride of Vector3 | GravityScale of single - | Gravity of Vector3 - + | GravityIgnore + /// Compute local gravity based on the given world gravity. static member localize gravityWorld gravity = match gravity with | GravityWorld -> gravityWorld - | GravityIgnore -> v3Zero + | GravityOverride gravity -> gravity | GravityScale scale -> gravityWorld * scale - | Gravity gravity -> gravity + | GravityIgnore -> v3Zero /// The properties needed to describe the physical part of a body. type BodyProperties = diff --git a/Nu/Nu/Render/Renderer2d.fs b/Nu/Nu/Render/Renderer2d.fs index 04ffc2c6d8..9e7dd7a1ec 100644 --- a/Nu/Nu/Render/Renderer2d.fs +++ b/Nu/Nu/Render/Renderer2d.fs @@ -321,7 +321,7 @@ type [] GlRenderer2d = static member private tryGetRenderAsset (assetTag : AssetTag) renderer = let mutable assetInfo = Unchecked.defaultof // OPTIMIZATION: seems like TryGetValue allocates here if we use the tupling idiom (this may only be the case in Debug builds tho). if renderer.RenderAssetCached.CachedAssetTagOpt :> obj |> notNull && - assetEq assetTag renderer.RenderAssetCached.CachedAssetTagOpt then + assetTag = renderer.RenderAssetCached.CachedAssetTagOpt then renderer.RenderAssetCached.CachedAssetTagOpt <- assetTag // NOTE: this isn't redundant because we want to trigger refEq early-out. ValueSome renderer.RenderAssetCached.CachedRenderAsset elif diff --git a/Nu/Nu/Render/Renderer3d.fs b/Nu/Nu/Render/Renderer3d.fs index fae3d0a487..72bfac9872 100644 --- a/Nu/Nu/Render/Renderer3d.fs +++ b/Nu/Nu/Render/Renderer3d.fs @@ -975,7 +975,7 @@ type [] private AnimatedModelSurfaceKey = let mutable equal = true let mutable i = 0 while i < left.BoneTransforms.Length && equal do - equal <- m4Eq left.BoneTransforms.[i] right.BoneTransforms.[i] + equal <- left.BoneTransforms.[i] = right.BoneTransforms.[i] i <- inc i equal && OpenGL.PhysicallyBased.PhysicallyBasedSurfaceFns.equals left.AnimatedSurface right.AnimatedSurface else false @@ -1079,7 +1079,7 @@ type [] private RenderTasks = OpenGL.PhysicallyBased.PhysicallyBasedSurfaceFns.equals static_.Key staticCached.Key && static_.Value.Count = staticCached.Value.Count && (static_.Value, staticCached.Value) - ||> Seq.forall2 (fun struct (m, cs, _, _, _) struct (mCached, csCached, _, _, _) -> m4Eq m mCached && cs = csCached)) + ||> Seq.forall2 (fun struct (m, cs, _, _, _) struct (mCached, csCached, _, _, _) -> m = mCached && cs = csCached)) let deferredStaticPreBatchesCached = renderTasks.DeferredStaticPreBatches.Count = renderTasksCached.DeferredStaticPreBatches.Count && (renderTasks.DeferredStaticPreBatches, renderTasksCached.DeferredStaticPreBatches) @@ -1091,7 +1091,7 @@ type [] private RenderTasks = OpenGL.PhysicallyBased.PhysicallyBasedSurfaceFns.equals static_.Key staticCached.Key && static_.Value.Count = staticCached.Value.Count && (static_.Value, staticCached.Value) - ||> Seq.forall2 (fun struct (m, cs, _, _, _) struct (mCached, csCached, _, _, _) -> m4Eq m mCached && cs = csCached)) + ||> Seq.forall2 (fun struct (m, cs, _, _, _) struct (mCached, csCached, _, _, _) -> m = mCached && cs = csCached)) let deferredStaticClippedPreBatchesCached = renderTasks.DeferredStaticClippedPreBatches.Count = renderTasksCached.DeferredStaticClippedPreBatches.Count && (renderTasks.DeferredStaticClippedPreBatches, renderTasksCached.DeferredStaticClippedPreBatches) @@ -1103,20 +1103,20 @@ type [] private RenderTasks = AnimatedModelSurfaceKey.equals animated.Key animatedCached.Key && animated.Value.Count = animatedCached.Value.Count && (animated.Value, animatedCached.Value) - ||> Seq.forall2 (fun struct (m, cs, _, _, _) struct (mCached, csCached, _, _, _) -> m4Eq m mCached && cs = csCached)) + ||> Seq.forall2 (fun struct (m, cs, _, _, _) struct (mCached, csCached, _, _, _) -> m = mCached && cs = csCached)) let deferredTerrainsCached = renderTasks.DeferredTerrains.Count = renderTasksCached.DeferredTerrains.Count && (renderTasks.DeferredTerrains, renderTasksCached.DeferredTerrains) ||> Seq.forall2 (fun struct (terrainDescriptor, patchDescriptor, _) struct (terrainDescriptorCached, patchDescriptorCached, _) -> patchDescriptor = patchDescriptorCached && - box3Eq terrainDescriptor.Bounds terrainDescriptorCached.Bounds && + terrainDescriptor.Bounds = terrainDescriptorCached.Bounds && terrainDescriptor.CastShadow = terrainDescriptorCached.CastShadow && terrainDescriptor.HeightMap = terrainDescriptorCached.HeightMap) let forwardCached = renderTasks.Forward.Count = renderTasksCached.Forward.Count && (renderTasks.Forward, renderTasksCached.Forward) ||> Seq.forall2 (fun struct (_, _, m, cs, _, _, _, bo, s, _) struct (_, _, mCached, csCached, _, _, _, boCached, sCached, _) -> - m4Eq m mCached && + m = mCached && cs = csCached && bo = boCached && // TODO: P0: optimize? OpenGL.PhysicallyBased.PhysicallyBasedSurfaceFns.equals s sCached) @@ -1500,7 +1500,7 @@ type [] GlRenderer3d = static member private tryGetRenderAsset (assetTag : AssetTag) renderer = let mutable assetInfo = Unchecked.defaultof // OPTIMIZATION: seems like TryGetValue allocates here if we use the tupling idiom (this may only be the case in Debug builds tho). if renderer.RenderAssetCached.CachedAssetTagOpt :> obj |> notNull && - assetEq assetTag renderer.RenderAssetCached.CachedAssetTagOpt then + assetTag = renderer.RenderAssetCached.CachedAssetTagOpt then renderer.RenderAssetCached.CachedAssetTagOpt <- assetTag // NOTE: this isn't redundant because we want to trigger refEq early-out. ValueSome renderer.RenderAssetCached.CachedRenderAsset elif @@ -2444,7 +2444,7 @@ type [] GlRenderer3d = | NormalPass -> Presence.intersects3d (ValueSome frustumInterior) frustumExterior frustumImposter (ValueSome lightBox) false true presence lightBounds | _ -> false if unculled then - let coneOuter = match light.LightType with SpotLight (_, coneOuter) -> min coneOuter MathF.PI_MINUS_EPSILON | _ -> MathF.TWO_PI + let coneOuter = match light.LightType with SpotLight (_, coneOuter) -> min coneOuter MathF.TWO_PI | _ -> MathF.TWO_PI let coneInner = match light.LightType with SpotLight (coneInner, _) -> min coneInner coneOuter | _ -> MathF.TWO_PI let light = { SortableLightId = 0UL @@ -2770,7 +2770,7 @@ type [] GlRenderer3d = | RenderLight3d rl -> let direction = rl.Rotation.Down let renderTasks = GlRenderer3d.getRenderTasks rl.RenderPass renderer - let coneOuter = match rl.LightType with SpotLight (_, coneOuter) -> min coneOuter MathF.PI_MINUS_EPSILON | _ -> MathF.TWO_PI + let coneOuter = match rl.LightType with SpotLight (_, coneOuter) -> min coneOuter MathF.TWO_PI | _ -> MathF.TWO_PI let coneInner = match rl.LightType with SpotLight (coneInner, _) -> min coneInner coneOuter | _ -> MathF.TWO_PI let light = { SortableLightId = rl.LightId diff --git a/Nu/Nu/Render/RendererImGui.fs b/Nu/Nu/Render/RendererImGui.fs index f008d141ca..15de3ef17f 100644 --- a/Nu/Nu/Render/RendererImGui.fs +++ b/Nu/Nu/Render/RendererImGui.fs @@ -193,7 +193,7 @@ type GlRendererImGui let now = DateTimeOffset.Now let assetTags = Array.ofSeq assetTextureRequests.Keys // eager copy to allow modification during enumeration let mutable assetTagsEnr = (seq assetTags).GetEnumerator () - while assetTagsEnr.MoveNext () && DateTimeOffset.Now - now <= TimeSpan.FromMilliseconds 4 do + while assetTagsEnr.MoveNext () && DateTimeOffset.Now - now <= TimeSpan.FromMilliseconds 4.0 do let assetTag = assetTagsEnr.Current if not (assetTextureOpts.ContainsKey assetTag) then match Metadata.tryGetFilePath assetTag with diff --git a/Nu/Nu/Render/RendererPrelude.fs b/Nu/Nu/Render/RendererPrelude.fs index cba41873a7..cba2ef8051 100644 --- a/Nu/Nu/Render/RendererPrelude.fs +++ b/Nu/Nu/Render/RendererPrelude.fs @@ -78,7 +78,7 @@ type [] RenderPass = match this with | LightMapPass (id, bounds) -> match that with - | LightMapPass (id2, bounds2) -> id = id2 && box3Eq bounds bounds2 + | LightMapPass (id2, bounds2) -> id = id2 && bounds = bounds2 | _ -> false | ShadowPass (id, indexInfoOpt, lightType, rotation, frustum) -> match that with @@ -87,11 +87,11 @@ type [] RenderPass = (match indexInfoOpt with | Some (index, view, projection) -> match indexInfoOpt2 with - | Some (index2, view2, projection2) -> index = index2 && m4Eq view view2 && m4Eq projection projection2 + | Some (index2, view2, projection2) -> index = index2 && view = view2 && projection = projection2 | None -> false | None -> indexInfoOpt2.IsNone) && lightType = lightType2 && - quatEq rotation rotation2 && + rotation = rotation2 && frustum = frustum2 | _ -> false | ReflectionPass (id, frustum) -> diff --git a/Nu/Nu/Render/RendererProcess.fs b/Nu/Nu/Render/RendererProcess.fs index 7b333128e0..0b9aaff2eb 100644 --- a/Nu/Nu/Render/RendererProcess.fs +++ b/Nu/Nu/Render/RendererProcess.fs @@ -441,7 +441,7 @@ type RendererThread () = // acknowledge swap request swapRequestAcknowledged <- true - // swap, optionally finishing + // swap match window with SglWindow window -> SDL.SDL_GL_SwapWindow window.SglWindow // clean up 3d diff --git a/Nu/Nu/Transform/Presence.fs b/Nu/Nu/Transform/Presence.fs index 998c523057..ce939c069a 100644 --- a/Nu/Nu/Transform/Presence.fs +++ b/Nu/Nu/Transform/Presence.fs @@ -52,21 +52,4 @@ type [] Presence = | Interior -> match frustumInteriorOpt with ValueSome frustumInterior -> frustumInterior.Intersects bounds | ValueNone -> false | Exterior -> frustumExterior.Intersects bounds || (match frustumInteriorOpt with ValueSome frustumInterior -> frustumInterior.Intersects bounds | ValueNone -> false) | Imposter -> frustumImposter.Intersects bounds - | Omnipresent -> true - -/// Presence operators. -[] -module PresenceOperators = - - /// Test two presence values for equality without allocating. - let presenceEq left right = - match struct (left, right) with - | struct (Interior, Interior) - | struct (Exterior, Exterior) - | struct (Imposter, Imposter) - | struct (Omnipresent, Omnipresent) -> true - | struct (_, _) -> false - - /// Test two presence values for inequality. - let inline presenceNeq left right = - not (presenceEq left right) \ No newline at end of file + | Omnipresent -> true \ No newline at end of file diff --git a/Nu/Nu/Transform/Transform.fs b/Nu/Nu/Transform/Transform.fs index 676fadc019..7a7c4f06bf 100644 --- a/Nu/Nu/Transform/Transform.fs +++ b/Nu/Nu/Transform/Transform.fs @@ -325,8 +325,8 @@ type [] Transform = /// Test transforms for equality. static member equalsByRef (left : Transform inref, right : Transform inref) = left.Flags_ = right.Flags_ && - v3Eq left.Position_ right.Position_ && - quatEq left.Rotation_ right.Rotation_ && + left.Position_ = right.Position_ && + left.Rotation_ = right.Rotation_ && v3EqApprox left.Scale_ right.Scale_ 0.0001f && // NOTE: using approx here since scale tends to be pulled from an affine matrix. Also, just guessing at espilon... left.Offset_.Equals right.Offset_ && left.Size_.Equals right.Size_ && diff --git a/Nu/Nu/World/World.fs b/Nu/Nu/World/World.fs index 267c145125..1c78528493 100644 --- a/Nu/Nu/World/World.fs +++ b/Nu/Nu/World/World.fs @@ -507,10 +507,7 @@ module WorldModule4 = // make the world's subsystems, loading initial packages where applicable let imGui = ImGui (false, windowViewport.Bounds.Size) - let physicsEngine2d = - match Constants.Physics.PhysicsEngine2d with - | Aether -> AetherPhysicsEngine.make (Constants.Physics.GravityDefault * Constants.Engine.Meter2d) - | Box2dNet -> Box2dNetPhysicsEngine.make (Constants.Physics.GravityDefault * Constants.Engine.Meter2d) + let physicsEngine2d = plugin.MakePhysicsEngine2d () let physicsEngine3d = JoltPhysicsEngine.make Constants.Physics.GravityDefault let joltDebugRendererImGuiOpt = new JoltDebugRendererImGui () let rendererProcess = diff --git a/Nu/Nu/World/WorldAssets.fs b/Nu/Nu/World/WorldAssets.fs index cd084f3d00..3526575419 100644 --- a/Nu/Nu/World/WorldAssets.fs +++ b/Nu/Nu/World/WorldAssets.fs @@ -78,4 +78,12 @@ module Assets = let [] LightProbeModel = asset PackageName Assets.Default.LightProbeModelName let [] AnimatedModel = asset PackageName Assets.Default.AnimatedModelName let [] Sound = asset PackageName Assets.Default.SoundName - let [] Song = asset PackageName Assets.Default.SongName \ No newline at end of file + let [] Song = asset PackageName Assets.Default.SongName + let [] RawIconIcon = asset PackageName Assets.Default.RawIconName + let [] TileMapIcon = asset PackageName Assets.Default.TileMapIconName + let [] SpineSkeletonIcon = asset PackageName Assets.Default.SpineSkeletonIconName + let [] StaticModelIcon = asset PackageName Assets.Default.StaticModelIconName + let [] AnimatedModelIcon = asset PackageName Assets.Default.AnimatedModelIconName + let [] SoundIcon = asset PackageName Assets.Default.SoundIconName + let [] SongIcon = asset PackageName Assets.Default.SongIconName + let [] Icons = Set.map (asset PackageName) Assets.Default.IconNames diff --git a/Nu/Nu/World/WorldAudio.fs b/Nu/Nu/World/WorldAudio.fs index a6668af462..a9af9a25bb 100644 --- a/Nu/Nu/World/WorldAudio.fs +++ b/Nu/Nu/World/WorldAudio.fs @@ -79,8 +79,8 @@ module WorldAudio = audioPlayer.SongFadingOut /// Send a message to the audio system to play a sound. - static member playSound volume sound world = - let playSoundMessage = PlaySoundMessage { Sound = sound; Volume = volume } + static member playSound distance panning volume sound world = + let playSoundMessage = PlaySoundMessage { Distance = distance; Panning = panning; Volume = volume; Sound = sound } World.enqueueAudioMessage playSoundMessage world /// Send a message to the audio system to play a song. diff --git a/Nu/Nu/World/WorldConfigure.fs b/Nu/Nu/World/WorldConfigure.fs index d2aa33645f..eeb1d57568 100644 --- a/Nu/Nu/World/WorldConfigure.fs +++ b/Nu/Nu/World/WorldConfigure.fs @@ -50,8 +50,8 @@ module Configure = | nameof Constants.Render.ShadowCascadeLimits -> Constants.Render.ShadowCascadeLimits <- scvalue value | nameof Constants.Render.ShadowCascadeMarginRatio -> Constants.Render.ShadowCascadeMarginRatio <- scvalue value | nameof Constants.Render.ShadowCascadeMarginRatioCull -> Constants.Render.ShadowCascadeMarginRatioCull <- scvalue value - | nameof Constants.Physics.PhysicsEngine2d -> Constants.Physics.PhysicsEngine2d <- scvalue value | nameof Constants.Physics.Collision2dSteps -> Constants.Physics.Collision2dSteps <- scvalue value + | nameof Constants.Physics.Collision2dFrameCompensation -> Constants.Physics.Collision2dFrameCompensation <- scvalue value | nameof Constants.Physics.Collision3dBodiesMax -> Constants.Physics.Collision3dBodiesMax <- scvalue value | nameof Constants.Physics.Collision3dBodyPairsMax -> Constants.Physics.Collision3dBodyPairsMax <- scvalue value | nameof Constants.Physics.Collision3dContactConstraintsMax -> Constants.Physics.Collision3dContactConstraintsMax <- scvalue value diff --git a/Nu/Nu/World/WorldConstants.fs b/Nu/Nu/World/WorldConstants.fs index 44e9228132..ee3976c40f 100644 --- a/Nu/Nu/World/WorldConstants.fs +++ b/Nu/Nu/World/WorldConstants.fs @@ -11,8 +11,8 @@ module Dissolve = /// The default 'dissolving' transition behavior of screens. let Default = - { IncomingTime = GameTime.ofSeconds 0.5f - OutgoingTime = GameTime.ofSeconds 1.0f + { IncomingTime = GameTime.ofSeconds 0.5 + OutgoingTime = GameTime.ofSeconds 1.0 DissolveImage = Assets.Default.Black } [] @@ -21,5 +21,5 @@ module Slide = /// The default 'slide show' behavior of slide screens. let Default = { DissolveDescriptor = Dissolve.Default - IdlingTime = GameTime.ofSeconds 1.0f + IdlingTime = GameTime.ofSeconds 1.0 SlideImageOpt = Some Assets.Default.NuSlide } \ No newline at end of file diff --git a/Nu/Nu/World/WorldContent.fs b/Nu/Nu/World/WorldContent.fs index 05ae67150c..ee1e0760b3 100644 --- a/Nu/Nu/World/WorldContent.fs +++ b/Nu/Nu/World/WorldContent.fs @@ -162,8 +162,9 @@ module Content = let childrenPotentiallyAltered = OrderedDictionary HashIdentity.Structural let childrenAdded = List () for childEntry in childContents do - match childContentsOld.TryGetValue childEntry.Key with - | (true, childContentOld) when optEq childEntry.Value.DispatcherNameOpt childContentOld.DispatcherNameOpt -> + let mutable childContentOld = Unchecked.defaultof<_> + if childContentsOld.TryGetValue (childEntry.Key, &childContentOld) && + childEntry.Value.DispatcherNameOpt = childContentOld.DispatcherNameOpt then let childSimulant = // OPTIMIZATION: attempt to get child simulant from old content rather than deriving it, and store it for future use. if isNull (childContentOld.SimulantCachedOpt :> obj) then let derived = World.deriveFromNames (Array.add childEntry.Key simulant.SimulantAddress.Names) :?> 'child @@ -174,15 +175,17 @@ module Content = childEntry.Value.SimulantCachedOpt <- found found childrenPotentiallyAltered.Add (childSimulant, childEntry.Value) - | (_, _) -> + else let childSimulant = World.deriveFromNames (Array.add childEntry.Key simulant.SimulantAddress.Names) :?> 'child childEntry.Value.SimulantCachedOpt <- childSimulant childrenAdded.Add (childSimulant, childEntry.Value) let childrenRemoved = List<'child> () for childEntryOld in childContentsOld do - match childContents.TryGetValue childEntryOld.Key with - | (true, childContentOld) when optEq childEntryOld.Value.DispatcherNameOpt childContentOld.DispatcherNameOpt -> () - | (_, _) -> + let mutable childContentOld = Unchecked.defaultof<_> + if childContents.TryGetValue (childEntryOld.Key, &childContentOld) && + childEntryOld.Value.DispatcherNameOpt = childContentOld.DispatcherNameOpt then + () // nothing to do + else let childSimulant = childEntryOld.Value.SimulantCachedOpt :?> 'child // OPTIMIZATION: because of above optimization, should be guaranteed to exist. childrenRemoved.Add childSimulant childrenPotentiallyAltered.Remove childSimulant |> ignore diff --git a/Nu/Nu/World/WorldDispatchers.fs b/Nu/Nu/World/WorldDispatchers.fs index 6e44381beb..cd1aebfaab 100644 --- a/Nu/Nu/World/WorldDispatchers.fs +++ b/Nu/Nu/World/WorldDispatchers.fs @@ -322,7 +322,7 @@ type Character2dDispatcher () = [define Entity.MountOpt None define Entity.CelSize (v2 28.0f 28.0f) define Entity.CelRun 8 - define Entity.AnimationDelay (GameTime.ofSeconds (1.0f / 15.0f)) + define Entity.AnimationDelay (GameTime.ofSeconds (1.0 / 15.0)) define Entity.BodyType Dynamic define Entity.AngularFactor v3Zero define Entity.SleepingAllowed true @@ -585,7 +585,7 @@ type RigidModelDispatcher () = let entity = evt.Subscriber : Entity match entity.GetBodyType world with | Static -> entity.SetNavShape BoundsNavShape world - | Kinematic | KinematicCharacter | Dynamic | DynamicCharacter | Vehicle -> entity.SetNavShape NavShape.EmptyNavShape world + | Kinematic | KinematicCharacter | Dynamic | DynamicCharacter | Vehicle -> entity.SetNavShape EmptyNavShape world Cascade static member Facets = @@ -595,7 +595,7 @@ type RigidModelDispatcher () = static member Properties = [define Entity.BodyShape (StaticModelShape { StaticModel = Assets.Default.StaticModel; Profile = Convex; TransformOpt = None; PropertiesOpt = None }) - define Entity.NavShape StaticModelNavShape] + define Entity.NavShape ContourNavShape] override this.Register (entity, world) = World.monitor updateBodyShape entity.StaticModel.ChangeEvent entity world @@ -674,7 +674,7 @@ type RigidModelSurfaceDispatcher () = static member Properties = [define Entity.BodyShape (StaticModelSurfaceShape { StaticModel = Assets.Default.StaticModel; SurfaceIndex = 0; Profile = Convex; TransformOpt = None; PropertiesOpt = None }) - define Entity.NavShape StaticModelSurfaceNavShape] + define Entity.NavShape ContourNavShape] override this.Register (entity, world) = World.monitor updateBodyShape entity.StaticModel.ChangeEvent entity world diff --git a/Nu/Nu/World/WorldEntity.fs b/Nu/Nu/World/WorldEntity.fs index deb302d053..d27e13f444 100644 --- a/Nu/Nu/World/WorldEntity.fs +++ b/Nu/Nu/World/WorldEntity.fs @@ -423,10 +423,11 @@ module WorldEntityModule = member this.AutoBounds world = World.autoBoundsEntity this world /// Set an entity's mount while adjusting its mount properties such that they do not change. - member this.SetMountOptWithAdjustment (value : Entity Address option) world = + member this.SetMountOptWithAdjustment assumeChange (value : Entity Address option) world = match (Option.bind (flip tryResolve this) (this.GetMountOpt world), Option.bind (flip tryResolve this) value) with | (Some mountOld, Some mountNew) -> - if mountOld <> mountNew && mountOld.GetExists world && mountNew.GetExists world then + let adjustmentDesired = assumeChange || mountOld <> mountNew + if adjustmentDesired && mountOld.GetExists world && mountNew.GetExists world then let affineMatrixMount = World.getEntityAffineMatrix mountNew world let affineMatrixMounter = World.getEntityAffineMatrix this world let affineMatrixLocal = affineMatrixMounter * affineMatrixMount.Inverted @@ -516,14 +517,14 @@ module WorldEntityModule = let mutable transformOld = this.GetTransform world let mutable transformNew = transformOld if this.GetIs2d world then - if v3Neq transformOld.PerimeterCenter center || - quatNeq transformOld.Rotation rotation then + if transformOld.PerimeterCenter <> center || + transformOld.Rotation <> rotation then transformNew.PerimeterCenter <- center transformNew.Rotation <- rotation this.SetTransformByRefWithoutEvent (&transformNew, world) else - if v3Neq transformOld.Position center || - quatNeq transformOld.Rotation rotation then + if transformOld.Position <> center || + transformOld.Rotation <> rotation then transformNew.Position <- center transformNew.Rotation <- rotation this.SetTransformByRefWithoutEvent (&transformNew, world) @@ -608,8 +609,7 @@ module WorldEntityModule = if source.Parent <> destination.Parent && Option.isSome mountOpt && World.getEntityAllowedToMount destination world then - destination.SetMountOptWithAdjustment None world // NOTE: we have to set mount to none in order to convince the engine it's changing. - destination.SetMountOptWithAdjustment mountOpt world + destination.SetMountOptWithAdjustment true mountOpt world /// Rename an entity. static member renameEntity source destination world = @@ -903,7 +903,7 @@ module WorldEntityModule = if descendantSource.GetExists world && descendantSource.HasPropagationTargets world then World.setEntityPropagationSourceOpt (Some descendantSource) descendentEntity world |> ignore let mountOpt = match parent with :? Entity -> Some Address.parent | _ -> None - entity.SetMountOptWithAdjustment mountOpt world + entity.SetMountOptWithAdjustment false mountOpt world entity /// Paste an entity. diff --git a/Nu/Nu/World/WorldEntityHierarchy.fs b/Nu/Nu/World/WorldEntityHierarchy.fs index 48b7fc495e..58cf6516dd 100644 --- a/Nu/Nu/World/WorldEntityHierarchy.fs +++ b/Nu/Nu/World/WorldEntityHierarchy.fs @@ -96,7 +96,7 @@ module WorldEntityHierarchyExtensions = //let concave = OpenGL.PhysicallyBased.PhysicallyBasedSurfaceFns.extractConcave concave staticModelMetadata.SceneOpt surface let surfaceShape = { surfaceShape with Profile = profile } child.SetBodyShape (StaticModelSurfaceShape surfaceShape) world - let navShape = OpenGL.PhysicallyBased.PhysicallyBasedSurfaceFns.extractNavShape StaticModelSurfaceNavShape staticModelMetadata.SceneOpt surface + let navShape = OpenGL.PhysicallyBased.PhysicallyBasedSurfaceFns.extractNavShape ContourNavShape staticModelMetadata.SceneOpt surface child.SetNavShape navShape world child else World.createEntity mountOpt DefaultOverlay (Some surnames) group world @@ -328,7 +328,7 @@ module Permafreezer3dDispatcherExtensions = let frozenShapes = getFrozenShapes this world for (bounds, matrix, staticModel, surfaceIndex, navShape, _, _) in frozenShapes do let navId = { NavIndex = index; NavEntity = this } - World.setNav3dBodyOpt (Some (bounds, matrix, staticModel, surfaceIndex, navShape)) navId world + World.setNav3dBodyOpt (Some (bounds, matrix, StaticModelSurfaceNavBody (staticModel, surfaceIndex), navShape)) navId world index <- inc index member internal this.RegisterFrozenShapesPhysics getFrozenShapes world = diff --git a/Nu/Nu/World/WorldEvents.fs b/Nu/Nu/World/WorldEvents.fs index d2adba2614..2883b7b26c 100644 --- a/Nu/Nu/World/WorldEvents.fs +++ b/Nu/Nu/World/WorldEvents.fs @@ -4,7 +4,6 @@ namespace Nu open System open System.Numerics -open System.Collections.Concurrent open Prime /// The data for a life-cycle event. diff --git a/Nu/Nu/World/WorldFacets.fs b/Nu/Nu/World/WorldFacets.fs index 1dff1cbaa0..05a16bec43 100644 --- a/Nu/Nu/World/WorldFacets.fs +++ b/Nu/Nu/World/WorldFacets.fs @@ -116,10 +116,12 @@ type AnimatedSpriteFacet () = let celRun = entity.GetCelRun world if celCount <> 0 && celRun <> 0 then let localTime = world.GameTime - startTime - let cel = int (localTime / entity.GetAnimationDelay world) % celCount * entity.GetAnimationStride world + let animationDelay = entity.GetAnimationDelay world + let animationStride = entity.GetAnimationStride world + let cel = int64 (localTime / animationDelay) % int64 celCount * int64 animationStride let celSize = entity.GetCelSize world - let celI = cel % celRun - let celJ = cel / celRun + let celI = cel % int64 celRun + let celJ = cel / int64 celRun let celX = single celI * celSize.X let celY = single celJ * celSize.Y let inset = box2 (v2 celX celY) celSize @@ -131,7 +133,7 @@ type AnimatedSpriteFacet () = define Entity.CelSize (Vector2 (32.0f, 32.0f)) define Entity.CelCount 16 define Entity.CelRun 4 - define Entity.AnimationDelay (GameTime.ofSeconds (1.0f / 15.0f)) + define Entity.AnimationDelay (GameTime.ofSeconds (1.0 / 15.0)) define Entity.AnimationStride 1 define Entity.AnimationSheet Assets.Default.AnimatedSprite define Entity.ClipOpt None @@ -274,7 +276,7 @@ type BasicStaticSpriteEmitterFacet () = static let handleEmitterImageChange evt world = let emitterImage = evt.Data.Value :?> Image AssetTag - mapEmitter (fun emitter -> if assetNeq emitter.Image emitterImage then { emitter with Image = emitterImage } else emitter) evt.Subscriber world + mapEmitter (fun emitter -> if emitter.Image <> emitterImage then { emitter with Image = emitterImage } else emitter) evt.Subscriber world Cascade static let handleEmitterLifeTimeOptChange evt world = @@ -321,7 +323,7 @@ type BasicStaticSpriteEmitterFacet () = | Some (:? Particles.BasicStaticSpriteEmitter as emitter) -> let position = entity.GetPosition world let emitter = - if v3Neq emitter.Body.Position position + if emitter.Body.Position <> position then { emitter with Body = { emitter.Body with Position = position }} else emitter { particleSystem with Emitters = Map.add typeof.Name (emitter :> Particles.Emitter) particleSystem.Emitters } @@ -337,7 +339,7 @@ type BasicStaticSpriteEmitterFacet () = | Some (:? Particles.BasicStaticSpriteEmitter as emitter) -> let angles = entity.GetAngles world let emitter = - if v3Neq emitter.Body.Angles angles + if emitter.Body.Angles <> angles then { emitter with Body = { emitter.Body with Angles = angles }} else emitter { particleSystem with Emitters = Map.add typeof.Name (emitter :> Particles.Emitter) particleSystem.Emitters } @@ -351,10 +353,10 @@ type BasicStaticSpriteEmitterFacet () = define Entity.EmitterClipOpt None define Entity.EmitterImage Assets.Default.Image define Entity.EmitterLifeTimeOpt GameTime.zero - define Entity.ParticleLifeTimeMaxOpt (GameTime.ofSeconds 1.0f) + define Entity.ParticleLifeTimeMaxOpt (GameTime.ofSeconds 1.0) define Entity.ParticleRate (match Constants.GameTime.DesiredFrameRate with StaticFrameRate _ -> 1.0f | DynamicFrameRate _ -> 60.0f) define Entity.ParticleMax 60 - define Entity.BasicParticleSeed { Life = Particles.Life.make GameTime.zero (GameTime.ofSeconds 1.0f); Body = Particles.Body.defaultBody; Size = Constants.Engine.Particle2dSizeDefault; Offset = v3Zero; Inset = box2Zero; Color = Color.One; Emission = Color.Zero; Flip = FlipNone } + define Entity.BasicParticleSeed { Life = Particles.Life.make GameTime.zero (GameTime.ofSeconds 1.0); Body = Particles.Body.defaultBody; Size = Constants.Engine.Particle2dSizeDefault; Offset = v3Zero; Inset = box2Zero; Color = Color.One; Emission = Color.Zero; Flip = FlipNone } define Entity.EmitterConstraint Particles.Constraint.empty define Entity.EmitterStyle "BasicStaticSpriteEmitter" nonPersistent Entity.ParticleSystem Particles.ParticleSystem.empty] @@ -581,7 +583,7 @@ type ButtonFacet () = let eventTrace = EventTrace.debug "ButtonFacet" "handleMouseLeftUp" "Click" EventTrace.empty World.publishPlus () entity.ClickEvent eventTrace entity true false world match entity.GetClickSoundOpt world with - | Some clickSound -> World.playSound (entity.GetClickSoundVolume world) clickSound world + | Some clickSound -> World.playSound 0.0f 0.0f (entity.GetClickSoundVolume world) clickSound world | None -> () Resolve else Cascade @@ -681,7 +683,7 @@ type ToggleButtonFacet () = let eventTrace = EventTrace.debug "ToggleFacet" "handleMouseLeftUp" "Toggle" EventTrace.empty World.publishPlus toggled entity.ToggleEvent eventTrace entity true false world match entity.GetToggleSoundOpt world with - | Some toggleSound -> World.playSound (entity.GetToggleSoundVolume world) toggleSound world + | Some toggleSound -> World.playSound 0.0f 0.0f (entity.GetToggleSoundVolume world) toggleSound world | None -> () Resolve else Cascade @@ -788,7 +790,7 @@ type RadioButtonFacet () = let eventTrace = EventTrace.debug "RadioButtonFacet" "handleMouseLeftUp" "Dial" EventTrace.empty World.publishPlus dialed entity.DialEvent eventTrace entity true false world match entity.GetDialSoundOpt world with - | Some dialSound -> World.playSound (entity.GetDialSoundVolume world) dialSound world + | Some dialSound -> World.playSound 0.0f 0.0f (entity.GetDialSoundVolume world) dialSound world | None -> () Resolve else Cascade @@ -2153,8 +2155,8 @@ type SpineSkeletonFacet () = spineSkeletonState.SpineSkeleton.ScaleX <- scaleX spineSkeletonState.SpineSkeleton.ScaleY <- scaleY spineSkeletonState.SpineAnimationState.TimeScale <- entity.GetSpineAnimationSpeed world - spineSkeletonState.SpineSkeleton.Update gameDelta.Seconds - spineSkeletonState.SpineAnimationState.Update gameDelta.Seconds + spineSkeletonState.SpineSkeleton.Update gameDelta.SecondsF + spineSkeletonState.SpineAnimationState.Update gameDelta.SecondsF spineSkeletonState.SpineAnimationState.Apply spineSkeletonState.SpineSkeleton |> ignore spineSkeletonState.SpineSkeleton.UpdateWorldTransform Spine.Skeleton.Physics.Update spineSkeletonState.SpineAnimationState.remove_Start startDelegate @@ -2818,10 +2820,12 @@ type AnimatedBillboardFacet () = let celRun = entity.GetCelRun world if celCount <> 0 && celRun <> 0 then let localTime = world.GameTime - startTime - let cel = int (localTime / entity.GetAnimationDelay world) % celCount * entity.GetAnimationStride world + let animationDelay = entity.GetAnimationDelay world + let animationStride = entity.GetAnimationStride world + let cel = int64 (localTime / animationDelay) % int64 celCount * int64 animationStride let celSize = entity.GetCelSize world - let celI = cel % celRun - let celJ = cel / celRun + let celI = cel % int64 celRun + let celJ = cel / int64 celRun let celX = single celI * celSize.X let celY = single celJ * celSize.Y let inset = box2 (v2 celX celY) celSize @@ -2833,7 +2837,7 @@ type AnimatedBillboardFacet () = define Entity.CelSize (Vector2 (32.0f, 32.0f)) define Entity.CelCount 16 define Entity.CelRun 4 - define Entity.AnimationDelay (GameTime.ofSeconds (1.0f / 15.0f)) + define Entity.AnimationDelay (GameTime.ofSeconds (1.0 / 15.0)) define Entity.AnimationStride 1 define Entity.MaterialProperties MaterialProperties.defaultProperties define Entity.Material Material.defaultMaterial @@ -3020,7 +3024,7 @@ type BasicStaticBillboardEmitterFacet () = | Some (:? Particles.BasicStaticBillboardEmitter as emitter) -> let position = entity.GetPosition world let emitter = - if v3Neq emitter.Body.Position position + if emitter.Body.Position <> position then { emitter with Body = { emitter.Body with Position = position }} else emitter { particleSystem with Emitters = Map.add typeof.Name (emitter :> Particles.Emitter) particleSystem.Emitters } @@ -3036,7 +3040,7 @@ type BasicStaticBillboardEmitterFacet () = | Some (:? Particles.BasicStaticBillboardEmitter as emitter) -> let angles = entity.GetAngles world let emitter = - if v3Neq emitter.Body.Angles angles + if emitter.Body.Angles <> angles then { emitter with Body = { emitter.Body with Angles = angles }} else emitter { particleSystem with Emitters = Map.add typeof.Name (emitter :> Particles.Emitter) particleSystem.Emitters } @@ -3049,10 +3053,10 @@ type BasicStaticBillboardEmitterFacet () = define Entity.EmitterMaterialProperties MaterialProperties.defaultProperties define Entity.EmitterMaterial Material.defaultMaterial define Entity.EmitterLifeTimeOpt GameTime.zero - define Entity.ParticleLifeTimeMaxOpt (GameTime.ofSeconds 1.0f) + define Entity.ParticleLifeTimeMaxOpt (GameTime.ofSeconds 1.0) define Entity.ParticleRate (match Constants.GameTime.DesiredFrameRate with StaticFrameRate _ -> 1.0f | DynamicFrameRate _ -> 60.0f) define Entity.ParticleMax 60 - define Entity.BasicParticleSeed { Life = Particles.Life.make GameTime.zero (GameTime.ofSeconds 1.0f); Body = Particles.Body.defaultBody; Size = v3Dup 0.25f; Offset = v3Zero; Inset = box2Zero; Color = Color.One; Emission = Color.Zero; Flip = FlipNone } + define Entity.BasicParticleSeed { Life = Particles.Life.make GameTime.zero (GameTime.ofSeconds 1.0); Body = Particles.Body.defaultBody; Size = v3Dup 0.25f; Offset = v3Zero; Inset = box2Zero; Color = Color.One; Emission = Color.Zero; Flip = FlipNone } define Entity.EmitterConstraint Particles.Constraint.empty define Entity.EmitterStyle "BasicStaticBillboardEmitter" define Entity.EmitterRenderStyle Deferred @@ -3839,7 +3843,7 @@ module TraversalInterpolatedFacetExtensions = match prevOpt with | ValueSome (previousTime, previousValue) -> let deltaTime = time - previousTime - let deltaTime = deltaTime.Seconds + let deltaTime = deltaTime.SecondsF if deltaTime > 0.0f then (sum + 0.5f * (previousValue + value) * deltaTime, totalTime + deltaTime, ValueSome (time, value)) else (sum, totalTime, ValueSome (time, value)) @@ -3871,7 +3875,7 @@ module TraversalInterpolatedFacetExtensions = match prevOpt with | ValueSome (previousTime, previousRotation) -> let deltaTime = time - previousTime - let deltaTime = deltaTime.Seconds + let deltaTime = deltaTime.SecondsF if deltaTime > 0.0f then let midpoint = Quaternion.Slerp (previousRotation, rotation, 0.5f) (sum + midpoint * deltaTime, totalTime + deltaTime, ValueSome (time, rotation)) @@ -3938,7 +3942,7 @@ type NavBodyFacet () = static let propagateNavBody (entity : Entity) world = let navId = { NavIndex = -1; NavEntity = entity } match entity.GetNavShape world with - | NavShape.EmptyNavShape -> + | EmptyNavShape -> if entity.GetIs2d world then () // TODO: implement for 2d navigation when it's available. else World.setNav3dBodyOpt None navId world @@ -3949,15 +3953,19 @@ type NavBodyFacet () = if entity.GetNavEnabled world then let bounds = entity.GetBounds world let affineMatrix = entity.GetAffineMatrix world - let staticModel = entity.GetStaticModel world - let surfaceIndex = entity.GetSurfaceIndex world - World.setNav3dBodyOpt (Some (bounds, affineMatrix, staticModel, surfaceIndex, shape)) navId world + match (entity.TryGet (nameof Entity.StaticModel) world, entity.TryGet (nameof Entity.SurfaceIndex) world) with + | (ValueSome staticModel, ValueNone) -> + World.setNav3dBodyOpt (Some (bounds, affineMatrix, StaticModelNavBody staticModel, shape)) navId world + | (ValueSome staticModel, ValueSome surfaceIndex) -> + World.setNav3dBodyOpt (Some (bounds, affineMatrix, StaticModelSurfaceNavBody (staticModel, surfaceIndex), shape)) navId world + | (_, _) -> + match entity.TryGet (nameof Entity.HeightMap) world with + | ValueSome heightMap -> World.setNav3dBodyOpt (Some (bounds, affineMatrix, HeightMapNavBody heightMap, shape)) navId world + | ValueNone -> World.setNav3dBodyOpt None navId world else World.setNav3dBodyOpt None navId world static member Properties = - [define Entity.StaticModel Assets.Default.StaticModel - define Entity.SurfaceIndex 0 - define Entity.NavShape BoundsNavShape + [define Entity.NavShape ContourNavShape define Entity.NavEnabled true] override this.Register (entity, world) = @@ -3993,7 +4001,7 @@ type NavBodyFacet () = Cascade let callback4 _ world = unsubscribe world; Cascade match entity.GetNavShape world with - | NavShape.EmptyNavShape -> () + | EmptyNavShape -> () | _ -> subscribe world World.sense callback (entity.ChangeEvent (nameof entity.NavShape)) entity (nameof NavBodyFacet) world World.sense callback2 (entity.ChangeEvent (nameof entity.NavEnabled)) entity (nameof NavBodyFacet) world @@ -4004,6 +4012,7 @@ type NavBodyFacet () = let callbackPnb evt world = propagateNavBody evt.Subscriber world; Cascade World.sense callbackPnb (entity.ChangeEvent (nameof entity.StaticModel)) entity (nameof NavBodyFacet) world World.sense callbackPnb (entity.ChangeEvent (nameof entity.SurfaceIndex)) entity (nameof NavBodyFacet) world + World.sense callbackPnb (entity.ChangeEvent (nameof entity.HeightMap)) entity (nameof NavBodyFacet) world propagateNavBody entity world override this.Unregister (entity, world) = diff --git a/Nu/Nu/World/WorldImGui.fs b/Nu/Nu/World/WorldImGui.fs index 37bdc9cc98..0ed7615c46 100644 --- a/Nu/Nu/World/WorldImGui.fs +++ b/Nu/Nu/World/WorldImGui.fs @@ -277,8 +277,8 @@ module WorldImGui = if ImGui.BeginCombo (name, caseName) then for case' in cases do let caseName' = case'.Name - if ImGui.Selectable (caseName', strEq caseName' caseName) then - if strNeq caseName caseName' then + if ImGui.Selectable (caseName', (caseName' = caseName)) then + if caseName <> caseName' then caseNameEdited <- true caseName <- caseName' ImGui.EndCombo () @@ -386,8 +386,8 @@ module WorldImGui = elif ty.GenericTypeArguments.[0] = typeof then (true, Activator.CreateInstance (ty, [|Assets.Default.Song :> obj|])) elif ty.GenericTypeArguments.[0] = typeof then (true, Activator.CreateInstance (ty, [|Assets.Default.StaticModel :> obj|])) elif ty.GenericTypeArguments.[0] = typeof then (true, Activator.CreateInstance (ty, [|Assets.Default.AnimatedModel :> obj|])) - elif ty.GenericTypeArguments.[0] = typeof then (true, Activator.CreateInstance (ty, [|{ Volume = Constants.Audio.SongVolumeDefault; Sound = Assets.Default.Sound } :> obj|])) - elif ty.GenericTypeArguments.[0] = typeof then (true, Activator.CreateInstance (ty, [|{ FadeInTime = GameTime.zero; FadeOutTime = Constants.Audio.FadeOutTimeDefault; StartTime = GameTime.zero; RepeatLimitOpt = None; Volume = Constants.Audio.SongVolumeDefault; Song = Assets.Default.Song } :> obj|])) + elif ty.GenericTypeArguments.[0] = typeof then (true, Activator.CreateInstance (ty, [|SoundDescriptor.defaultDescriptor :> obj|])) + elif ty.GenericTypeArguments.[0] = typeof then (true, Activator.CreateInstance (ty, [|SongDescriptor.defaultDescriptor :> obj|])) elif ty.GenericTypeArguments.[0] = typeof then (true, Activator.CreateInstance (ty, [|NoScatter :> obj|])) elif ty.GenericTypeArguments.[0].IsGenericType && ty.GenericTypeArguments.[0].GetGenericTypeDefinition () = typedefof<_ array> then (true, Activator.CreateInstance (ty, [|Reflection.objsToArray ty.GenericTypeArguments.[0] []|])) elif ty.GenericTypeArguments.[0].IsGenericType && ty.GenericTypeArguments.[0].GetGenericTypeDefinition () = typedefof<_ list> then (true, Activator.CreateInstance (ty, [|Reflection.objsToList ty.GenericTypeArguments.[0] []|])) @@ -478,8 +478,8 @@ module WorldImGui = elif ty.GenericTypeArguments.[0] = typeof then (true, createValueOption Assets.Default.Song) elif ty.GenericTypeArguments.[0] = typeof then (true, createValueOption Assets.Default.StaticModel) elif ty.GenericTypeArguments.[0] = typeof then (true, createValueOption Assets.Default.AnimatedModel) - elif ty.GenericTypeArguments.[0] = typeof then (true, createValueOption { Volume = Constants.Audio.SongVolumeDefault; Sound = Assets.Default.Sound }) - elif ty.GenericTypeArguments.[0] = typeof then (true, createValueOption { FadeInTime = GameTime.zero; FadeOutTime = Constants.Audio.FadeOutTimeDefault; StartTime = GameTime.zero; RepeatLimitOpt = None; Volume = Constants.Audio.SongVolumeDefault; Song = Assets.Default.Song }) + elif ty.GenericTypeArguments.[0] = typeof then (true, createValueOption SoundDescriptor.defaultDescriptor) + elif ty.GenericTypeArguments.[0] = typeof then (true, createValueOption SongDescriptor.defaultDescriptor) elif ty.GenericTypeArguments.[0] = typeof then (true, createValueOption NoScatter) elif ty.GenericTypeArguments.[0].IsGenericType && ty.GenericTypeArguments.[0].GetGenericTypeDefinition () = typedefof<_ array> then (true, createValueOption (Reflection.objsToArray ty.GenericTypeArguments.[0] [])) elif ty.GenericTypeArguments.[0].IsGenericType && ty.GenericTypeArguments.[0].GetGenericTypeDefinition () = typedefof<_ list> then (true, createValueOption (Reflection.objsToList ty.GenericTypeArguments.[0] [])) @@ -529,13 +529,13 @@ module WorldImGui = let (edited4, value) = if not (NativePtr.isNullPtr (ImGui.AcceptDragDropPayload "Asset").NativePtr) then match context.DragDropPayloadOpt with - | Some payload -> - try let valueStrEscaped = payload + | Some (DragDropAsset (assetTagStr, _)) -> + try let valueStrEscaped = assetTagStr let valueStrUnescaped = String.unescape valueStrEscaped let value = converter.ConvertFromString valueStrUnescaped (true, value) with _ -> (false, value) - | None -> (false, value) + | Some _ | None -> (false, value) else (false, value) ImGui.EndDragDropTarget () (edited4, value) @@ -721,13 +721,13 @@ module WorldImGui = if ImGui.IsItemFocused () then context.FocusProperty () let mutable index = match substance with Mass _ -> 0 | Density _ -> 1 ImGui.SameLine () - let result = + let (edited, substance) = if ImGui.Combo (name, &index, [|nameof Mass; nameof Density|], 2) || edited then let substance = match index with 0 -> Mass scalar | 1 -> Density scalar | _ -> failwithumf () - (false, true, substance :> obj) - else (false, false, substance :> obj) + (true, substance :> obj) + else (false, substance :> obj) if ImGui.IsItemFocused () then context.FocusProperty () - result + (false, edited, substance) | :? Animation as animation -> let tryReplaceAnimationName (fieldInfo : PropertyInfo) (field : obj) = match (fieldInfo.Name, context.SelectedEntityOpt) with @@ -742,8 +742,8 @@ module WorldImGui = let mutable animationNameEdited = false if ImGui.BeginCombo (name, animationName) then for animationName' in animationNames do - if String.notEmpty animationName' && ImGui.Selectable (animationName', strEq animationName' animationName) then - if strNeq animationName animationName' then + if String.notEmpty animationName' && ImGui.Selectable (animationName', (animationName' = animationName)) then + if animationName <> animationName' then animationName <- animationName' animationNameEdited <- true ImGui.EndCombo () @@ -760,7 +760,7 @@ module WorldImGui = | :? Material as material -> World.imGuiEditPropertyRecord false name (typeof) material context world | :? Justification as justification -> - let (promoted, caseNameEdited, caseName) = World.imGuiSelectCase name ty justification context + let (_, caseNameEdited, caseName) = World.imGuiSelectCase name ty justification context let justification = if caseNameEdited then match caseName with @@ -768,21 +768,21 @@ module WorldImGui = | nameof Unjustified -> Unjustified true | _ -> failwithumf () else justification - match justification with - | Justified (h, v) -> - ImGui.Indent () - let (promoted2, edited, h) = World.imGuiEditProperty "JustificationH" (getType h) h context world - let (promoted3, edited2, v) = World.imGuiEditProperty "JustificationV" (getType v) v context world - ImGui.Text "(wrapping unavailable when justified)" - ImGui.Unindent () - (promoted || promoted2 || promoted3, caseNameEdited || edited || edited2, Justified (h :?> JustificationH, v :?> JustificationV)) - | Unjustified wrapped -> - ImGui.Indent () - let (promoted2, edited, wrapped) = World.imGuiEditProperty "Wrapped" (getType wrapped) wrapped context world - ImGui.Unindent () - (promoted || promoted2, caseNameEdited || edited, Unjustified (wrapped :?> bool)) + ImGui.Indent () + let (edited, justification) = + match justification with + | Justified (h, v) -> + let (_, edited, h) = World.imGuiEditProperty "JustificationH" (getType h) h context world + let (_, edited2, v) = World.imGuiEditProperty "JustificationV" (getType v) v context world + ImGui.Text "(wrapping unavailable when justified)" + (caseNameEdited || edited || edited2, Justified (h :?> JustificationH, v :?> JustificationV)) + | Unjustified wrapped -> + let (_, edited, wrapped) = World.imGuiEditProperty "Wrapped" (getType wrapped) wrapped context world + (caseNameEdited || edited, Unjustified (wrapped :?> bool)) + ImGui.Unindent () + (false, edited, justification) | :? FlowLimit as limit -> - let (promoted, caseNameEdited, caseName) = World.imGuiSelectCase name ty limit context + let (_, caseNameEdited, caseName) = World.imGuiSelectCase name ty limit context let limit = if caseNameEdited then match caseName with @@ -791,14 +791,42 @@ module WorldImGui = | nameof FlowTo -> FlowTo 32.0f | _ -> failwithumf () else limit - match limit with - | FlowParent -> (promoted, caseNameEdited, limit) - | FlowUnlimited -> (promoted, caseNameEdited, limit) - | FlowTo limit -> - let (promoted2, edited, limit) = World.imGuiEditProperty "Limit" (getType limit) limit context world - (promoted || promoted2, caseNameEdited || edited, FlowTo (limit :?> single)) + ImGui.Indent () + let (edited, value) = + match limit with + | FlowParent -> (caseNameEdited, limit) + | FlowUnlimited -> (caseNameEdited, limit) + | FlowTo limit -> + let (_, edited, limit) = World.imGuiEditProperty "Limit" (getType limit) limit context world + (caseNameEdited || edited, FlowTo (limit :?> single)) + ImGui.Unindent () + (false, edited, value) + | :? Gravity as gravity -> + let (_, caseNameEdited, caseName) = World.imGuiSelectCase name ty gravity context + let gravity = + if caseNameEdited then + match caseName with + | nameof GravityWorld -> GravityWorld + | nameof GravityOverride -> GravityOverride Constants.Physics.GravityDefault + | nameof GravityScale -> GravityScale 1.0f + | nameof GravityIgnore -> GravityIgnore + | _ -> failwithumf () + else gravity + ImGui.Indent () + let (edited, gravity) = + match gravity with + | GravityWorld -> (caseNameEdited, gravity) + | GravityOverride gravity -> + let (_, edited, gravity) = World.imGuiEditProperty "Gravity" (getType gravity) gravity context world + (caseNameEdited || edited, GravityOverride (gravity :?> Vector3)) + | GravityScale scale -> + let (_, edited, scale) = World.imGuiEditProperty "Scale" (getType scale) scale context world + (caseNameEdited || edited, GravityScale (scale :?> single)) + | GravityIgnore -> (caseNameEdited, gravity) + ImGui.Unindent () + (false, edited, gravity) | :? Layout as layout -> - let (promoted, caseNameEdited, caseName) = World.imGuiSelectCase name ty layout context + let (_, caseNameEdited, caseName) = World.imGuiSelectCase name ty layout context let layout = if caseNameEdited then match caseName with @@ -830,7 +858,7 @@ module WorldImGui = (caseNameEdited || edited || edited2 || edited3, Grid (dims :?> Vector2i, flowDirectionOpt :?> FlowDirection option, resizeChildren :?> bool)) | Manual -> (caseNameEdited, layout) ImGui.Unindent () - (promoted, edited, layout) + (false, edited, layout) | :? Lighting3dConfig as lighting3dConfig -> let mutable lighting3dEdited = false let mutable lightCutoffMargin = lighting3dConfig.LightCutoffMargin @@ -915,7 +943,7 @@ module WorldImGui = lighting3dEdited <- ImGui.SliderFloat ("Tone Map Saturation", &toneMapSaturation, 0.0f, 2.0f) || lighting3dEdited; if ImGui.IsItemFocused () then context.FocusProperty () if toneMapType = ReinhardExtendedToneMap.Enumerate then lighting3dEdited <- ImGui.SliderFloat ("Tone Map White Point", &toneMapWhitePoint, 0.0f, 20.0f) || lighting3dEdited; if ImGui.IsItemFocused () then context.FocusProperty () - ImGui.Text "Global Fog" + ImGui.Text "Distance Fog" lighting3dEdited <- ImGui.Checkbox ("Fog Enabled", &fogEnabled) || lighting3dEdited; if ImGui.IsItemFocused () then context.FocusProperty () lighting3dEdited <- ImGui.Combo ("Fog Type", &fogType, FogType.Names, FogType.Names.Length) || lighting3dEdited; if ImGui.IsItemFocused () then context.FocusProperty () if fogType = LinearFog.Enumerate then @@ -1077,8 +1105,8 @@ module WorldImGui = if ImGui.BeginCombo ("ParitionType", partitionTypeStr, ImGuiComboFlags.HeightLarge) then let partitionTypeStrs = Array.map (fun (ptv : RcPartitionType) -> ptv.Name) RcPartitionType.Values for partitionTypeStr' in partitionTypeStrs do - if ImGui.Selectable (partitionTypeStr', strEq partitionTypeStr' partitionTypeStr) then - if strNeq partitionTypeStr partitionTypeStr' then + if ImGui.Selectable (partitionTypeStr', (partitionTypeStr' = partitionTypeStr)) then + if partitionTypeStr <> partitionTypeStr' then partitionTypeStr <- partitionTypeStr' nav3dConfigEdited <- true ImGui.EndCombo () @@ -1204,30 +1232,7 @@ module WorldImGui2 = let segments = Dictionary () let circles = Dictionary () let physicsEngine2d = World.getPhysicsEngine2d world - let renderContext : PhysicsEngineRenderContext = - match Constants.Physics.PhysicsEngine2d with - | Aether -> - { new AetherPhysicsEngineRenderContext with - override this.DrawLine (start : Vector2, stop : Vector2, color) = - match segments.TryGetValue color with - | (true, segmentList) -> segmentList.Add (start, stop) - | (false, _) -> segments.Add (color, List [struct (start, stop)]) - override this.DrawCircle (center : Vector2, radius, color) = - match circles.TryGetValue struct (color, radius) with - | (true, circleList) -> circleList.Add center - | (false, _) -> circles.Add (struct (color, radius), List [center]) - override _.EyeBounds = world.Eye2dBounds } - | Box2dNet -> - { new Box2dNetPhysicsEngineRenderContext with - override this.DrawLine (start : Vector2, stop : Vector2, color) = - match segments.TryGetValue color with - | (true, segmentList) -> segmentList.Add (start, stop) - | (false, _) -> segments.Add (color, List [struct (start, stop)]) - override this.DrawCircle (center : Vector2, radius, color) = - match circles.TryGetValue struct (color, radius) with - | (true, circleList) -> circleList.Add center - | (false, _) -> circles.Add (struct (color, radius), List [center]) - override _.EyeBounds = world.Eye2dBounds } + let renderContext = World.makePhysicsEngine2dRenderContext segments circles world physicsEngine2d.TryRender renderContext for struct (color, segmentList) in segments.Pairs' do World.imGuiSegments2d false segmentList 1.0f color world diff --git a/Nu/Nu/World/WorldImSim.fs b/Nu/Nu/World/WorldImSim.fs index 009e902292..58d4a578af 100644 --- a/Nu/Nu/World/WorldImSim.fs +++ b/Nu/Nu/World/WorldImSim.fs @@ -398,7 +398,7 @@ module WorldImSim = // create entity only when needed if entityCreation then let mountOpt = match mountOptOpt with ValueSome mountOpt -> mountOpt | ValueNone -> Some Address.parent - World.createEntity7 true typeof<'d>.Name mountOpt OverlayNameDescriptor.DefaultOverlay (Some entity.Surnames) entity.Group world |> ignore + World.createEntity7 true typeof<'d>.Name mountOpt DefaultOverlay (Some entity.Surnames) entity.Group world |> ignore // protect entity World.setEntityProtected true entity world |> ignore diff --git a/Nu/Nu/World/WorldModule.fs b/Nu/Nu/World/WorldModule.fs index 45d0e66138..16a2d12dae 100644 --- a/Nu/Nu/World/WorldModule.fs +++ b/Nu/Nu/World/WorldModule.fs @@ -917,6 +917,9 @@ module WorldModule = static member tryMakeEmitter time lifeTimeOpt particleLifeTimeMaxOpt particleRate particleMax emitterStyle (world : World) = world.WorldExtension.Plugin.TryMakeEmitter time lifeTimeOpt particleLifeTimeMaxOpt particleRate particleMax emitterStyle + static member internal makePhysicsEngine2dRenderContext segments circles (world : World) = + world.WorldExtension.Plugin.MakePhysicsEngine2dRenderContext segments circles world.Eye2dBounds + static member internal preProcess (world : World) = world.WorldExtension.Plugin.PreProcess world diff --git a/Nu/Nu/World/WorldModule2.fs b/Nu/Nu/World/WorldModule2.fs index 537b387026..4c38826f24 100644 --- a/Nu/Nu/World/WorldModule2.fs +++ b/Nu/Nu/World/WorldModule2.fs @@ -162,7 +162,7 @@ module WorldModule2 = match (selectedScreen.GetIncoming world).SongOpt with | Some playSong -> match World.getSongOpt world with - | Some song when assetEq song.Song playSong.Song -> () // do nothing when song is the same + | Some song when song.Song = playSong.Song -> () // do nothing when song is the same | _ -> World.playSong playSong.FadeInTime playSong.FadeOutTime GameTime.zero playSong.RepeatLimitOpt playSong.Volume playSong.Song world // play song when song is different | None -> () if world.Alive then @@ -177,7 +177,7 @@ module WorldModule2 = match (selectedScreen.GetIncoming world).SongOpt with | Some playSong -> match World.getSongOpt world with - | Some song when assetEq song.Song playSong.Song -> () // do nothing when song is the same + | Some song when song.Song = playSong.Song -> () // do nothing when song is the same | _ -> World.playSong playSong.FadeInTime playSong.FadeOutTime GameTime.zero playSong.RepeatLimitOpt playSong.Volume playSong.Song world // play song when song is different | None -> () match selectedScreen.GetSlideOpt world with @@ -242,7 +242,7 @@ module WorldModule2 = match destinationOpt with | Some destination -> match (incoming.SongOpt, (destination.GetIncoming world).SongOpt) with - | (Some song, Some song2) when assetEq song.Song song2.Song -> () // do nothing when song is the same + | (Some song, Some song2) when song.Song = song2.Song -> () // do nothing when song is the same | (None, None) -> () // do nothing when neither plays a song (allowing manual control) | (_, _) -> World.fadeOutSong playSong.FadeOutTime world // fade out when song is different | None -> @@ -312,7 +312,7 @@ module WorldModule2 = current.FadeOutTime <> song.FadeOutTime || current.StartTime <> song.StartTime || current.RepeatLimitOpt <> song.RepeatLimitOpt || - assetNeq current.Song song.Song then + current.Song <> song.Song then World.playSong song.FadeInTime song.FadeOutTime song.StartTime song.RepeatLimitOpt song.Volume song.Song world elif current.Volume <> song.Volume then World.setSongVolume song.Volume world diff --git a/Nu/Nu/World/WorldModuleEntity.fs b/Nu/Nu/World/WorldModuleEntity.fs index fc3e25b5a8..ac25859fe2 100644 --- a/Nu/Nu/World/WorldModuleEntity.fs +++ b/Nu/Nu/World/WorldModuleEntity.fs @@ -193,11 +193,11 @@ module WorldModuleEntity = static member internal publishTransformEvents (transformOld : Transform byref, transformNew : Transform byref, is2d, publishChangeEvents, entity : Entity, world) = if publishChangeEvents then - let positionChanged = v3Neq transformNew.Position transformOld.Position - let rotationChanged = quatNeq transformNew.Rotation transformOld.Rotation + let positionChanged = transformNew.Position <> transformOld.Position + let rotationChanged = transformNew.Rotation <> transformOld.Rotation let scaleChanged = v3NeqApprox transformNew.Scale transformOld.Scale 0.0001f // NOTE: just guessing at epsilon... - let offsetChanged = v3Neq transformNew.Offset transformOld.Offset - let sizeChanged = v3Neq transformNew.Size transformOld.Size + let offsetChanged = transformNew.Offset <> transformOld.Offset + let sizeChanged = transformNew.Size <> transformOld.Size let elevationChanged = transformNew.Elevation <> transformOld.Elevation let overflowChanged = transformNew.Overflow <> transformOld.Overflow World.publishEntityChange (nameof Transform) () () publishChangeEvents entity world // OPTIMIZATION: eliding data for computed change events for speed. @@ -860,7 +860,7 @@ module WorldModuleEntity = static member internal setEntityPresence (value : Presence) (entity : Entity) world = let entityState = World.getEntityState entity world let previous = entityState.Presence - if presenceNeq value previous then + if value <> previous then let visibleInViewOld = entityState.VisibleInView let staticInPlayOld = entityState.StaticInPlay let lightProbeOld = entityState.LightProbe @@ -970,7 +970,7 @@ module WorldModuleEntity = static member internal setEntityPosition value entity world = let entityState = World.getEntityState entity world - if v3Neq value entityState.Position then + if value <> entityState.Position then let mutable transform = entityState.Transform transform.Position <- value if entityState.Optimized world.Imperative @@ -983,7 +983,7 @@ module WorldModuleEntity = // ensure value changed let entityState = World.getEntityState entity world - if v3Neq value entityState.PositionLocal then + if value <> entityState.PositionLocal then // OPTIMIZATION: do updates and propagation in-place as much as possible. if entityState.Optimized world.Imperative then @@ -1040,7 +1040,7 @@ module WorldModuleEntity = static member internal setEntityRotation value entity world = let entityState = World.getEntityState entity world - if quatNeq value entityState.Rotation then + if value <> entityState.Rotation then let mutable transform = entityState.Transform transform.Rotation <- value if entityState.Optimized world.Imperative @@ -1053,7 +1053,7 @@ module WorldModuleEntity = // ensure value changed let entityState = World.getEntityState entity world - if quatNeq value entityState.RotationLocal then + if value <> entityState.RotationLocal then // OPTIMIZATION: do updates and propagation in-place as much as possible. let anglesLocal = value.RollPitchYaw @@ -1076,7 +1076,7 @@ module WorldModuleEntity = let previous = entityState.RotationLocal let previousAnglesLocal = entityState.AnglesLocal let previousDegreesLocal = entityState.DegreesLocal - if quatNeq value previous then + if value <> previous then let entityState = if world.Imperative then entityState.RotationLocal <- value @@ -1111,7 +1111,7 @@ module WorldModuleEntity = static member internal setEntityScale value entity world = let entityState = World.getEntityState entity world - if v3Neq value entityState.Scale then + if value <> entityState.Scale then let mutable transform = entityState.Transform transform.Scale <- value if entityState.Optimized world.Imperative @@ -1124,7 +1124,7 @@ module WorldModuleEntity = // ensure value changed let entityState = World.getEntityState entity world - if v3Neq value entityState.ScaleLocal then + if value <> entityState.ScaleLocal then // OPTIMIZATION: do updates and propagation in-place as much as possible. if entityState.Optimized world.Imperative then @@ -1143,7 +1143,7 @@ module WorldModuleEntity = // update ScaleLocal property let previous = entityState.ScaleLocal - if v3Neq value previous then + if value <> previous then let entityState = if world.Imperative then entityState.ScaleLocal <- value @@ -1174,7 +1174,7 @@ module WorldModuleEntity = static member internal setEntityOffset value entity world = let entityState = World.getEntityState entity world - if v3Neq value entityState.Offset then + if value <> entityState.Offset then let mutable transform = entityState.Transform transform.Offset <- value if entityState.Optimized world.Imperative @@ -1185,7 +1185,7 @@ module WorldModuleEntity = static member internal setEntitySize value entity world = let entityState = World.getEntityState entity world - if v3Neq value entityState.Size then + if value <> entityState.Size then let centerPrevious = entityState.PerimeterCenterLocal let bottomPrevious = entityState.PerimeterBottomLocal let bottomLeftPrevious = entityState.PerimeterBottomLeftLocal @@ -1208,7 +1208,7 @@ module WorldModuleEntity = static member internal setEntityAngles value entity world = let entityState = World.getEntityState entity world - if v3Neq value entityState.Angles then + if value <> entityState.Angles then let mutable transform = entityState.Transform transform.Angles <- value if entityState.Optimized world.Imperative @@ -1221,7 +1221,7 @@ module WorldModuleEntity = // ensure value changed let entityState = World.getEntityState entity world - if v3Neq value entityState.AnglesLocal then + if value <> entityState.AnglesLocal then // OPTIMIZATION: do updates and propagation in-place as much as possible. let rotationLocal = value.RollPitchYaw @@ -1512,7 +1512,7 @@ module WorldModuleEntity = static member internal setEntityPerimeterUnscaled value entity world = let entityState = World.getEntityState entity world - if box3Neq value entityState.PerimeterUnscaled then + if value <> entityState.PerimeterUnscaled then let mutable transform = entityState.Transform transform.PerimeterUnscaled <- value if entityState.Optimized world.Imperative @@ -1526,7 +1526,7 @@ module WorldModuleEntity = static member internal setEntityPerimeter value entity world = let entityState = World.getEntityState entity world - if box3Neq value entityState.Perimeter then + if value <> entityState.Perimeter then let mutable transform = entityState.Transform transform.Perimeter <- value if entityState.Optimized world.Imperative @@ -1753,7 +1753,7 @@ module WorldModuleEntity = else true else false - static member internal getEntityXtensionValue<'a> propertyName entity (world : World) = + static member internal tryGetEntityXtensionValueObj<'a> propertyName entity world : obj option = let entityStateOpt = World.getEntityStateOpt entity world match entityStateOpt :> obj with | null -> failwithf "Could not find entity '%s'." (scstring entity) @@ -1766,53 +1766,60 @@ module WorldModuleEntity = | :? ComputedProperty as cp -> cp.ComputedGet entity world | _ -> property.PropertyValue match valueObj with - | :? 'a as value -> value - | null -> null :> obj :?> 'a - | value -> - let value = - try value |> valueToSymbol |> symbolToValue + | :? 'a -> Some valueObj + | null -> null :> obj |> Some + | valueObj -> + let valueObj = + try valueObj |> valueToSymbol |> symbolToValue with _ -> - let value = typeof<'a>.GetDefaultValue () + let valueObj = typeof<'a>.GetDefaultValue () Log.warn "Could not gracefully promote value to the required type, so using a default value instead." - value :?> 'a + valueObj match property.PropertyValue with - | :? DesignerProperty as dp -> dp.DesignerType <- typeof<'a>; dp.DesignerValue <- value + | :? DesignerProperty as dp -> dp.DesignerType <- typeof<'a>; dp.DesignerValue <- valueObj | :? ComputedProperty -> () // nothing to do - | _ -> property.PropertyType <- typeof<'a>; property.PropertyValue <- value - value + | _ -> property.PropertyType <- typeof<'a>; property.PropertyValue <- valueObj + Some valueObj else - let value = + let valueObjOpt = match entityStateOpt.OverlayNameOpt with | Some overlayName -> match World.tryGetOverlayerPropertyValue propertyName typeof<'a> overlayName entityStateOpt.FacetNames world with - | Some value -> value :?> 'a + | Some value -> Some value | None -> let definitions = Reflection.getPropertyDefinitions (getType entityStateOpt.Dispatcher) match List.tryFind (fun (pd : PropertyDefinition) -> pd.PropertyName = propertyName) definitions with | Some definition -> match definition.PropertyExpr with - | DefineExpr value -> value :?> 'a - | VariableExpr eval -> eval world :?> 'a - | ComputedExpr property -> property.ComputedGet entity world :?> 'a - | None -> failwithumf () + | DefineExpr value -> Some value + | VariableExpr eval -> eval world |> Some + | ComputedExpr property -> property.ComputedGet entity world |> Some + | None -> None | None -> let definitions = Reflection.getPropertyDefinitions (getType entityStateOpt.Dispatcher) match List.tryFind (fun (pd : PropertyDefinition) -> pd.PropertyName = propertyName) definitions with | Some definition -> match definition.PropertyExpr with - | DefineExpr value -> value :?> 'a - | VariableExpr eval -> eval world :?> 'a - | ComputedExpr property -> property.ComputedGet entity world :?> 'a - | None -> failwithumf () - let property = { PropertyType = typeof<'a>; PropertyValue = value } - entityStateOpt.Xtension <- Xtension.attachProperty propertyName property entityStateOpt.Xtension - value + | DefineExpr value -> Some value + | VariableExpr eval -> eval world |> Some + | ComputedExpr property -> property.ComputedGet entity world |> Some + | None -> None + match valueObjOpt with + | Some valueObj -> + let property = { PropertyType = typeof<'a>; PropertyValue = valueObj } + entityStateOpt.Xtension <- Xtension.attachProperty propertyName property entityStateOpt.Xtension + Some valueObj + | None -> None static member internal tryGetEntityXtensionValue<'a> propertyName entity world : 'a voption = - // NOTE: we're only using exceptions as flow control in order to avoid code duplication and perf costs. - // TODO: P1: see if we can find a way to refactor this situation without incurring any additional overhead on the getEntityXtensionValue call. - try World.getEntityXtensionValue<'a> propertyName entity world |> ValueSome - with _ -> ValueNone + match World.tryGetEntityXtensionValueObj<'a> propertyName entity world with + | Some valueObj -> valueObj :?> 'a |> ValueSome + | None -> ValueNone + + static member internal getEntityXtensionValue<'a> propertyName entity (world : World) = + match World.tryGetEntityXtensionValueObj<'a> propertyName entity world with + | Some valueObj -> valueObj :?> 'a + | None -> failwithumf () static member internal getEntityProperty propertyName entity world = let mutable property = Unchecked.defaultof<_> @@ -1840,7 +1847,7 @@ module WorldModuleEntity = | Some computedSet -> let previous = cp.ComputedGet (box entity) (box world) if property.PropertyValue =/= previous then - computedSet property.PropertyValue entity world |> ignore // TODO: P0: same as the others. + computedSet property.PropertyValue entity world struct (true, true, previous) else struct (true, false, previous) | None -> struct (false, false, Unchecked.defaultof<_>) @@ -1924,7 +1931,7 @@ module WorldModuleEntity = previous <- cp.ComputedGet (box entity) (box world) if value =/= previous then changed <- true - computedSet propertyOld.PropertyValue entity world |> ignore // TODO: P0: same as the others. + computedSet propertyOld.PropertyValue entity world | None -> () | _ -> previous <- propertyOld.PropertyValue @@ -2658,9 +2665,9 @@ module WorldModuleEntity = staticInPlayNew <> staticInPlayOld || lightProbeNew <> lightProbeOld || lightNew <> lightOld || - presenceNeq presenceNew presenceOld || - presenceNeq presenceInPlayNew presenceInPlayOld || - box3Neq boundsOld boundsNew then + presenceNew <> presenceOld || + presenceInPlayNew <> presenceInPlayOld || + boundsOld <> boundsNew then // update entity in entity tree if entityState.Is2d then diff --git a/Nu/Nu/World/WorldModuleGame.fs b/Nu/Nu/World/WorldModuleGame.fs index 59957d44d5..dcdd50fb9d 100644 --- a/Nu/Nu/World/WorldModuleGame.fs +++ b/Nu/Nu/World/WorldModuleGame.fs @@ -217,7 +217,7 @@ module WorldModuleGame = static member internal setGameEye2dCenter value game world = let gameState = World.getGameState game world let previous = gameState.Eye2dCenter - if v2Neq previous value then + if previous <> value then World.setGameState { gameState with Eye2dCenter = value } game world World.publishGameChange (nameof gameState.Eye2dCenter) previous value game world true @@ -237,7 +237,7 @@ module WorldModuleGame = static member internal setGameEye2dSize value game world = let gameState = World.getGameState game world let previous = gameState.Eye2dSize - if v2Neq previous value then + if previous <> value then World.setGameState { gameState with Eye2dSize = value } game world World.publishGameChange (nameof gameState.Eye2dSize) previous value game world true @@ -318,7 +318,7 @@ module WorldModuleGame = static member internal setGameEye3dCenter (value : Vector3) game world = let gameState = World.getGameState game world let previous = gameState.Eye3dCenter - if v3Neq previous value then + if previous <> value then let viewportInterior = Viewport.makeInterior () let viewportExterior = Viewport.makeExterior () let viewportImposter = Viewport.makeImposter () @@ -347,7 +347,7 @@ module WorldModuleGame = static member internal setGameEye3dRotation value game world = let gameState = World.getGameState game world let previous = gameState.Eye3dRotation - if quatNeq previous value then + if previous <> value then let viewportInterior = Viewport.makeInterior () let viewportExterior = Viewport.makeExterior () let viewportImposter = Viewport.makeImposter () @@ -374,6 +374,7 @@ module WorldModuleGame = (World.getGameState game world).Eye3dFieldOfView static member internal setGameEye3dFieldOfView value game world = + let value = value |> max 0.001f |> min MathF.PI_MINUS_EPSILON let gameState = World.getGameState game world let previous = gameState.Eye3dFieldOfView if previous <> value then @@ -632,7 +633,7 @@ module WorldModuleGame = | _ -> true else false - static member internal getGameXtensionValue<'a> propertyName game world = + static member internal tryGetGameXtensionValueObj<'a> propertyName game world = let gameState = World.getGameState game world let mutable property = Unchecked.defaultof<_> if GameState.tryGetProperty (propertyName, gameState, &property) then @@ -642,39 +643,43 @@ module WorldModuleGame = | :? ComputedProperty as cp -> cp.ComputedGet game world | _ -> property.PropertyValue match valueObj with - | :? 'a as value -> value - | null -> null :> obj :?> 'a - | value -> - let value = - try value |> valueToSymbol |> symbolToValue + | :? 'a -> Some valueObj + | null -> null :> obj |> Some + | valueObj -> + let valueObj = + try valueObj |> valueToSymbol |> symbolToValue with _ -> - let value = typeof<'a>.GetDefaultValue () + let valueObj = typeof<'a>.GetDefaultValue () Log.warn "Could not gracefully promote value to the required type, so using a default value instead." - value :?> 'a + valueObj match property.PropertyValue with - | :? DesignerProperty as dp -> dp.DesignerType <- typeof<'a>; dp.DesignerValue <- value + | :? DesignerProperty as dp -> dp.DesignerType <- typeof<'a>; dp.DesignerValue <- valueObj | :? ComputedProperty -> () // nothing to do - | _ -> property.PropertyType <- typeof<'a>; property.PropertyValue <- value - value + | _ -> property.PropertyType <- typeof<'a>; property.PropertyValue <- valueObj + Some valueObj else let definitions = Reflection.getPropertyDefinitions (getType gameState.Dispatcher) - let value = + let valueObj = match List.tryFind (fun (pd : PropertyDefinition) -> pd.PropertyName = propertyName) definitions with | Some definition -> match definition.PropertyExpr with - | DefineExpr value -> value :?> 'a - | VariableExpr eval -> eval world :?> 'a - | ComputedExpr property -> property.ComputedGet game world :?> 'a + | DefineExpr valueObj -> valueObj + | VariableExpr eval -> eval world + | ComputedExpr property -> property.ComputedGet game world | None -> failwithumf () - let property = { PropertyType = typeof<'a>; PropertyValue = value } + let property = { PropertyType = typeof<'a>; PropertyValue = valueObj } gameState.Xtension <- Xtension.attachProperty propertyName property gameState.Xtension - value + Some valueObj static member internal tryGetGameXtensionValue<'a> propertyName game world : 'a voption = - // NOTE: we're only using exceptions as flow control in order to avoid code duplication and perf costs. - // TODO: P1: see if we can find a way to refactor this situation without incurring any additional overhead on the getGameXtensionValue call. - try World.getGameXtensionValue<'a> propertyName game world |> ValueSome - with _ -> ValueNone + match World.tryGetGameXtensionValueObj<'a> propertyName game world with + | Some valueObj -> valueObj :?> 'a |> ValueSome + | None -> ValueNone + + static member internal getGameXtensionValue<'a> propertyName game (world : World) = + match World.tryGetGameXtensionValueObj<'a> propertyName game world with + | Some valueObj -> valueObj :?> 'a + | None -> failwithumf () static member internal getGameProperty propertyName game world = match GameGetters.TryGetValue propertyName with @@ -701,7 +706,7 @@ module WorldModuleGame = | Some computedSet -> let previous = cp.ComputedGet (box game) (box world) if property.PropertyValue =/= previous then - computedSet property.PropertyValue game world |> ignore // TODO: P0: move related type definitions into Nu from Prime and modify them to match mutable usage. + computedSet property.PropertyValue game world struct (true, true, previous) else struct (true, false, previous) | None -> struct (false, false, Unchecked.defaultof<_>) @@ -756,7 +761,7 @@ module WorldModuleGame = previous <- cp.ComputedGet (box game) (box world) if value =/= previous then changed <- true - computedSet propertyOld.PropertyValue game world |> ignore // TODO: P0: move related type definitions into Nu from Prime and modify them to match mutable usage. + computedSet propertyOld.PropertyValue game world | None -> () | _ -> previous <- propertyOld.PropertyValue diff --git a/Nu/Nu/World/WorldModuleGroup.fs b/Nu/Nu/World/WorldModuleGroup.fs index 9ced7a80a3..fd650e4262 100644 --- a/Nu/Nu/World/WorldModuleGroup.fs +++ b/Nu/Nu/World/WorldModuleGroup.fs @@ -216,7 +216,7 @@ module WorldModuleGroup = | _ -> true else false - static member internal getGroupXtensionValue<'a> propertyName group world = + static member internal tryGetGroupXtensionValueObj<'a> propertyName group world = let groupState = World.getGroupState group world let mutable property = Unchecked.defaultof<_> if GroupState.tryGetProperty (propertyName, groupState, &property) then @@ -226,39 +226,43 @@ module WorldModuleGroup = | :? ComputedProperty as cp -> cp.ComputedGet group world | _ -> property.PropertyValue match valueObj with - | :? 'a as value -> value - | null -> null :> obj :?> 'a - | value -> - let value = - try value |> valueToSymbol |> symbolToValue + | :? 'a -> Some valueObj + | null -> null :> obj |> Some + | valueObj -> + let valueObj = + try valueObj |> valueToSymbol |> symbolToValue with _ -> - let value = typeof<'a>.GetDefaultValue () + let valueObj = typeof<'a>.GetDefaultValue () Log.warn "Could not gracefully promote value to the required type, so using a default value instead." - value :?> 'a + valueObj match property.PropertyValue with - | :? DesignerProperty as dp -> dp.DesignerType <- typeof<'a>; dp.DesignerValue <- value + | :? DesignerProperty as dp -> dp.DesignerType <- typeof<'a>; dp.DesignerValue <- valueObj | :? ComputedProperty -> () // nothing to do - | _ -> property.PropertyType <- typeof<'a>; property.PropertyValue <- value - value + | _ -> property.PropertyType <- typeof<'a>; property.PropertyValue <- valueObj + Some valueObj else let definitions = Reflection.getPropertyDefinitions (getType groupState.Dispatcher) - let value = + let valueObj = match List.tryFind (fun (pd : PropertyDefinition) -> pd.PropertyName = propertyName) definitions with | Some definition -> match definition.PropertyExpr with - | DefineExpr value -> value :?> 'a - | VariableExpr eval -> eval world :?> 'a - | ComputedExpr property -> property.ComputedGet group world :?> 'a + | DefineExpr valueObj -> valueObj + | VariableExpr eval -> eval world + | ComputedExpr property -> property.ComputedGet group world | None -> failwithumf () - let property = { PropertyType = typeof<'a>; PropertyValue = value } + let property = { PropertyType = typeof<'a>; PropertyValue = valueObj } groupState.Xtension <- Xtension.attachProperty propertyName property groupState.Xtension - value + Some valueObj static member internal tryGetGroupXtensionValue<'a> propertyName group world : 'a voption = - // NOTE: we're only using exceptions as flow control in order to avoid code duplication and perf costs. - // TODO: P1: see if we can find a way to refactor this situation without incurring any additional overhead on the getGroupXtensionValue call. - try World.getGroupXtensionValue<'a> propertyName group world |> ValueSome - with _ -> ValueNone + match World.tryGetGroupXtensionValueObj<'a> propertyName group world with + | Some valueObj -> valueObj :?> 'a |> ValueSome + | None -> ValueNone + + static member internal getGroupXtensionValue<'a> propertyName group (world : World) = + match World.tryGetGroupXtensionValueObj<'a> propertyName group world with + | Some valueObj -> valueObj :?> 'a + | None -> failwithumf () static member internal getGroupProperty propertyName group world = match GroupGetters.TryGetValue propertyName with @@ -285,7 +289,7 @@ module WorldModuleGroup = | Some computedSet -> let previous = cp.ComputedGet (box group) (box world) if property.PropertyValue =/= previous then - computedSet property.PropertyValue group world |> ignore // TODO: P0: move related type definitions into Nu from Prime and modify them to match mutable usage. + computedSet property.PropertyValue group world struct (true, true, previous) else struct (true, false, previous) | None -> struct (false, false, Unchecked.defaultof<_>) @@ -340,7 +344,7 @@ module WorldModuleGroup = previous <- cp.ComputedGet (box group) (box world) if value =/= previous then changed <- true - computedSet propertyOld.PropertyValue group world |> ignore // TODO: P0: move related type definitions into Nu from Prime and modify them to match mutable usage. + computedSet propertyOld.PropertyValue group world | None -> () | _ -> previous <- propertyOld.PropertyValue diff --git a/Nu/Nu/World/WorldModuleScreen.fs b/Nu/Nu/World/WorldModuleScreen.fs index 909a499ad2..f4cc812c07 100644 --- a/Nu/Nu/World/WorldModuleScreen.fs +++ b/Nu/Nu/World/WorldModuleScreen.fs @@ -263,7 +263,7 @@ module WorldModuleScreen = | _ -> true else false - static member internal getScreenXtensionValue<'a> propertyName screen world = + static member internal tryGetScreenXtensionValueObj<'a> propertyName screen world = let screenState = World.getScreenState screen world let mutable property = Unchecked.defaultof<_> if ScreenState.tryGetProperty (propertyName, screenState, &property) then @@ -273,39 +273,43 @@ module WorldModuleScreen = | :? ComputedProperty as cp -> cp.ComputedGet screen world | _ -> property.PropertyValue match valueObj with - | :? 'a as value -> value - | null -> null :> obj :?> 'a - | value -> - let value = - try value |> valueToSymbol |> symbolToValue + | :? 'a -> Some valueObj + | null -> null :> obj |> Some + | valueObj -> + let valueObj = + try valueObj |> valueToSymbol |> symbolToValue with _ -> - let value = typeof<'a>.GetDefaultValue () + let valueObj = typeof<'a>.GetDefaultValue () Log.warn "Could not gracefully promote value to the required type, so using a default value instead." - value :?> 'a + valueObj match property.PropertyValue with - | :? DesignerProperty as dp -> dp.DesignerType <- typeof<'a>; dp.DesignerValue <- value + | :? DesignerProperty as dp -> dp.DesignerType <- typeof<'a>; dp.DesignerValue <- valueObj | :? ComputedProperty -> () // nothing to do - | _ -> property.PropertyType <- typeof<'a>; property.PropertyValue <- value - value + | _ -> property.PropertyType <- typeof<'a>; property.PropertyValue <- valueObj + Some valueObj else let definitions = Reflection.getPropertyDefinitions (getType screenState.Dispatcher) - let value = + let valueObj = match List.tryFind (fun (pd : PropertyDefinition) -> pd.PropertyName = propertyName) definitions with | Some definition -> match definition.PropertyExpr with - | DefineExpr value -> value :?> 'a - | VariableExpr eval -> eval world :?> 'a - | ComputedExpr property -> property.ComputedGet screen world :?> 'a + | DefineExpr valueObj -> valueObj + | VariableExpr eval -> eval world + | ComputedExpr property -> property.ComputedGet screen world | None -> failwithumf () - let property = { PropertyType = typeof<'a>; PropertyValue = value } + let property = { PropertyType = typeof<'a>; PropertyValue = valueObj } screenState.Xtension <- Xtension.attachProperty propertyName property screenState.Xtension - value + Some valueObj static member internal tryGetScreenXtensionValue<'a> propertyName screen world : 'a voption = - // NOTE: we're only using exceptions as flow control in order to avoid code duplication and perf costs. - // TODO: P1: see if we can find a way to refactor this situation without incurring any additional overhead on the getScreenXtensionValue call. - try World.getScreenXtensionValue<'a> propertyName screen world |> ValueSome - with _ -> ValueNone + match World.tryGetScreenXtensionValueObj<'a> propertyName screen world with + | Some valueObj -> valueObj :?> 'a |> ValueSome + | None -> ValueNone + + static member internal getScreenXtensionValue<'a> propertyName screen (world : World) = + match World.tryGetScreenXtensionValueObj<'a> propertyName screen world with + | Some valueObj -> valueObj :?> 'a + | None -> failwithumf () static member internal getScreenProperty propertyName screen world = match ScreenGetters.TryGetValue propertyName with @@ -332,7 +336,7 @@ module WorldModuleScreen = | Some computedSet -> let previous = cp.ComputedGet (box screen) (box world) if property.PropertyValue =/= previous then - computedSet property.PropertyValue screen world |> ignore // TODO: P0: move related type definitions into Nu from Prime and modify them to match mutable usage. + computedSet property.PropertyValue screen world struct (true, true, previous) else struct (true, false, previous) | None -> struct (false, false, Unchecked.defaultof<_>) @@ -387,7 +391,7 @@ module WorldModuleScreen = previous <- cp.ComputedGet (box screen) (box world) if value =/= previous then changed <- true - computedSet propertyOld.PropertyValue screen world |> ignore // TODO: P0: move related type definitions into Nu from Prime and modify them to match mutable usage. + computedSet propertyOld.PropertyValue screen world | None -> () | _ -> previous <- propertyOld.PropertyValue diff --git a/Nu/Nu/World/WorldPrelude.fs b/Nu/Nu/World/WorldPrelude.fs index 801b441afd..cac0b9d072 100644 --- a/Nu/Nu/World/WorldPrelude.fs +++ b/Nu/Nu/World/WorldPrelude.fs @@ -355,8 +355,8 @@ type SlideDescriptor = IdlingTime : GameTime SlideImageOpt : Image AssetTag option } -/// Describes the shape of a desired overlay. -type OverlayNameDescriptor = +/// Specifies an overlay. +type OverlayDescriptor = | NoOverlay | RoutedOverlay | DefaultOverlay diff --git a/Nu/Nu/World/WorldScreen.fs b/Nu/Nu/World/WorldScreen.fs index ca468a9cb0..5ba6fd2e02 100644 --- a/Nu/Nu/World/WorldScreen.fs +++ b/Nu/Nu/World/WorldScreen.fs @@ -341,28 +341,34 @@ module WorldScreenModule = setScreenSlide slideDescriptor destination screen world static member internal getNav3dDescriptors contents = - [for (bounds : Box3, affineMatrix, staticModel, surfaceIndex, content) in contents do + [for (bounds : Box3, affineMatrix : Matrix4x4, nav3dBody, content) in contents do match content with - | NavShape.EmptyNavShape -> () - | NavShape.BoundsNavShape -> Left bounds - | NavShape.StaticModelSurfaceNavShape -> - match Metadata.tryGetStaticModelMetadata staticModel with - | ValueSome physicallyBasedModel -> - if surfaceIndex >= 0 && surfaceIndex < physicallyBasedModel.Surfaces.Length then - if bounds.Size.Magnitude < Constants.Nav.Bounds3dMagnitudeMax then - Right (bounds, affineMatrix, physicallyBasedModel.Surfaces.[surfaceIndex]) - else - Log.warn "Navigation shape bounds magnitude exceeded maximum; ignoring." - | ValueNone -> () - | NavShape.StaticModelNavShape -> - match Metadata.tryGetStaticModelMetadata staticModel with - | ValueSome physicallyBasedModel -> - for surface in physicallyBasedModel.Surfaces do - if bounds.Size.Magnitude < Constants.Nav.Bounds3dMagnitudeMax then - Right (bounds, affineMatrix, surface) - else - Log.warn "Navigation shape bounds magnitude exceeded maximum; ignoring." - | ValueNone -> ()] + | EmptyNavShape -> () + | BoundsNavShape -> Choice1Of3 bounds + | ContourNavShape -> + match nav3dBody with + | StaticModelNavBody staticModel -> + match Metadata.tryGetStaticModelMetadata staticModel with + | ValueSome physicallyBasedModel -> + for surface in physicallyBasedModel.Surfaces do + if bounds.Size.Magnitude < Constants.Nav.Bounds3dMagnitudeMax then + Choice2Of3 (bounds, affineMatrix, surface) + else + Log.warn "Navigation shape bounds magnitude exceeded maximum; ignoring." + | ValueNone -> () + | StaticModelSurfaceNavBody (staticModel, surfaceIndex) -> + match Metadata.tryGetStaticModelMetadata staticModel with + | ValueSome physicallyBasedModel -> + if surfaceIndex >= 0 && surfaceIndex < physicallyBasedModel.Surfaces.Length then + if bounds.Size.Magnitude < Constants.Nav.Bounds3dMagnitudeMax then + Choice2Of3 (bounds, affineMatrix, physicallyBasedModel.Surfaces.[surfaceIndex]) + else + Log.warn "Navigation shape bounds magnitude exceeded maximum; ignoring." + | ValueNone -> () + | HeightMapNavBody heightMap -> + match HeightMap.tryGetMetadata Metadata.tryGetFilePath bounds v2One heightMap with + | ValueSome heightMap -> Choice3Of3 (bounds, heightMap) + | ValueNone -> ()] static member internal trySaveNav3dMesh (navBuilderResultData : NavBuilderResultData) dtNavMesh filePathOpt = try match filePathOpt with @@ -392,14 +398,14 @@ module WorldScreenModule = let vertices = [|for descriptor in descriptors do match descriptor with - | Left bounds -> + | Choice1Of3 bounds -> match boundsOpt with | None -> boundsOpt <- Some bounds | Some (bounds' : Box3) -> boundsOpt <- Some (bounds'.Combine bounds) let corners = bounds.Corners for corner in corners do corner.X; corner.Y; corner.Z - | Right (bounds, affineMatrix : Matrix4x4, surface) -> + | Choice2Of3 (bounds, affineMatrix : Matrix4x4, surface) -> let geometry = surface.PhysicallyBasedGeometry match boundsOpt with | None -> boundsOpt <- Some bounds @@ -407,14 +413,20 @@ module WorldScreenModule = if geometry.PrimitiveType = OpenGL.PrimitiveType.Triangles then for v in geometry.Vertices do let v' = v.Transform affineMatrix - v'.X; v'.Y; v'.Z|] + v'.X; v'.Y; v'.Z + | Choice3Of3 (bounds, heightMap) -> + match boundsOpt with + | None -> boundsOpt <- Some bounds + | Some (bounds' : Box3) -> boundsOpt <- Some (bounds'.Combine bounds) + for struct (p, _) in heightMap.PositionsAndTexCoordses do + p.X; p.Y; p.Z|] // compute indices let mutable offset = 0 let indices = [|for descriptor in descriptors do match descriptor with - | Left _ -> + | Choice1Of3 _ -> // as the corners are ordered in Box3.Corners... // // 6--------7 @@ -426,30 +438,43 @@ module WorldScreenModule = // |/ |/ // 1--------2 // - offset + 2; offset + 3; offset + 7 // right - offset + 2; offset + 7; offset + 4 - offset + 0; offset + 1; offset + 5 // left - offset + 0; offset + 5; offset + 6 - offset + 4; offset + 5; offset + 6 // top - offset + 4; offset + 6; offset + 7 - offset + 0; offset + 1; offset + 2 // bottom - offset + 0; offset + 2; offset + 3 - offset + 0; offset + 3; offset + 7 // back - offset + 0; offset + 7; offset + 6 - offset + 1; offset + 2; offset + 4 // front - offset + 1; offset + 4; offset + 5 + yield offset + 2; yield offset + 3; yield offset + 7 // right + yield offset + 2; yield offset + 7; yield offset + 4 + yield offset + 0; yield offset + 1; yield offset + 5 // left + yield offset + 0; yield offset + 5; yield offset + 6 + yield offset + 4; yield offset + 5; yield offset + 6 // top + yield offset + 4; yield offset + 6; yield offset + 7 + yield offset + 0; yield offset + 1; yield offset + 2 // bottom + yield offset + 0; yield offset + 2; yield offset + 3 + yield offset + 0; yield offset + 3; yield offset + 7 // back + yield offset + 0; yield offset + 7; yield offset + 6 + yield offset + 1; yield offset + 2; yield offset + 4 // front + yield offset + 1; yield offset + 4; yield offset + 5 offset <- offset + 8 - | Right (_, _, surface) -> + | Choice2Of3 (_, _, surface) -> let geometry = surface.PhysicallyBasedGeometry if geometry.PrimitiveType = OpenGL.PrimitiveType.Triangles then for i in geometry.Indices do - i + offset - offset <- offset + geometry.Vertices.Length|] + yield offset + i + offset <- offset + geometry.Vertices.Length + | Choice3Of3 (_, heightMap) -> + for y in 0 .. dec heightMap.Resolution.Y - 1 do + for x in 0 .. dec heightMap.Resolution.X - 1 do + yield offset + heightMap.Resolution.X * y + x + yield offset + heightMap.Resolution.X * inc y + x + yield offset + heightMap.Resolution.X * y + inc x + yield offset + heightMap.Resolution.X * inc y + x + yield offset + heightMap.Resolution.X * inc y + inc x + yield offset + heightMap.Resolution.X * y + inc x + offset <- offset + heightMap.PositionsAndTexCoordses.Length|] // attempt to create geometry provider match boundsOpt with | Some bounds when vertices.Length >= 3 && indices.Length >= 3 -> - let provider = Nav3dInputGeomProvider (vertices, indices, bounds) + let boundsBoundsSize = v3Dup Constants.Nav.Bounds3dMagnitudeMax + let boundsBounds = box3 (bounds.Center - boundsBoundsSize * 0.5f) boundsBoundsSize + let boundsClipped = bounds.Clip boundsBounds + let provider = Nav3dInputGeomProvider (vertices, indices, boundsClipped) Some (provider :> IInputGeomProvider) | Some _ | None -> None @@ -610,7 +635,7 @@ module WorldScreenModule = /// Compute angular velocity for the given turn speed and navDirection. static member nav3dFace turnSpeed (rotation : Quaternion) (navDirection : Vector3) (world : World) = - let deltaTime = let gameDelta = world.GameDelta in gameDelta.Seconds + let deltaTime = let gameDelta = world.GameDelta in gameDelta.SecondsF let navRotationDesired = Quaternion.CreateFromAxisAngle (v3Up, atan2 navDirection.X navDirection.Z + MathF.PI) let navSign = (rotation.Forward.Cross navRotationDesired.Forward).Y let navAngleBetweenOpt = rotation.Forward.AngleBetween navRotationDesired.Forward @@ -627,7 +652,7 @@ module WorldScreenModule = /// Compute navigation information that results in following the given destination. static member nav3dFollow distanceMinOpt distanceMaxOpt moveSpeed turnSpeed (position : Vector3) (rotation : Quaternion) (destination : Vector3) screen (world : World) = - let deltaTime = let gameDelta = world.GameDelta in gameDelta.Seconds + let deltaTime = let gameDelta = world.GameDelta in gameDelta.SecondsF let distance = (destination - position).Magnitude if (Option.isNone distanceMinOpt || distance > distanceMinOpt.Value) && (Option.isNone distanceMaxOpt || distance <= distanceMaxOpt.Value) then diff --git a/Nu/Nu/World/WorldTypes.fs b/Nu/Nu/World/WorldTypes.fs index b29c2cb0d2..bf431d38f3 100644 --- a/Nu/Nu/World/WorldTypes.fs +++ b/Nu/Nu/World/WorldTypes.fs @@ -27,10 +27,10 @@ module internal WorldTypes = let mutable internal EmptyEntityContent = Unchecked.defaultof // Debugging F# reach-arounds. - let mutable internal viewGame = fun (_ : obj) (_ : obj) -> Array.create 0 (String.Empty, obj ()) - let mutable internal viewScreen = fun (_ : obj) (_ : obj) -> Array.create 0 (String.Empty, obj ()) - let mutable internal viewGroup = fun (_ : obj) (_ : obj) -> Array.create 0 (String.Empty, obj ()) - let mutable internal viewEntity = fun (_ : obj) (_ : obj) -> Array.create 0 (String.Empty, obj ()) + let mutable internal viewGame = fun (_ : obj) (_ : obj) -> Array.empty + let mutable internal viewScreen = fun (_ : obj) (_ : obj) -> Array.empty + let mutable internal viewGroup = fun (_ : obj) (_ : obj) -> Array.empty + let mutable internal viewEntity = fun (_ : obj) (_ : obj) -> Array.empty // EventGraph F# reach-arounds. let mutable internal getSelectedScreenIdling : obj -> bool = Unchecked.defaultof<_> @@ -272,12 +272,18 @@ and NavId = { NavEntity : Entity NavIndex : int } +/// Describes a navigable 3D body. +and Nav3dBody = + | StaticModelNavBody of StaticModel AssetTag + | StaticModelSurfaceNavBody of StaticModel AssetTag * int + | HeightMapNavBody of HeightMap + /// Represents 3d navigation capabilies for a screen. /// NOTE: this type is intended only for internal engine use. and [] Nav3d = { Nav3dContext : RcContext - Nav3dBodies : Map - Nav3dBodiesOldOpt : Map option + Nav3dBodies : Map + Nav3dBodiesOldOpt : Map option Nav3dConfig : Nav3dConfig Nav3dConfigOldOpt : Nav3dConfig option Nav3dMeshOpt : (string option * NavBuilderResultData * DtNavMesh * DtNavMeshQuery) option } @@ -291,13 +297,20 @@ and [] Nav3d = Nav3dConfigOldOpt = None Nav3dMeshOpt = None } +/// Represents a payload for editor drag and drop operations. +and DragDropPayload = + | DragDropAsset of AssetTagStr : string * AssetTag : AssetTag + | DragDropEntity of Entity : Entity + | DragDropUserDefined of obj + /// Context for editing behavior. +/// TODO: add a way to post a drag-drop payload. and EditContext = { Snapshot : SnapshotType -> World -> unit FocusProperty : unit -> unit UnfocusProperty : unit -> unit SearchAssetViewer : unit -> unit - DragDropPayloadOpt : string option + DragDropPayloadOpt : DragDropPayload option SnapDrag : single SelectedScreen : Screen SelectedGroup : Group @@ -2247,6 +2260,29 @@ and [] NuPlugin () = | "BasicStaticBillboardEmitter" -> Particles.BasicStaticBillboardEmitter.makeDefault time lifeTimeOpt particleLifeTimeOpt particleRate particleMax :> Particles.Emitter |> Some | _ -> None + /// Make the 2D physics engine for the engine to use. + abstract MakePhysicsEngine2d : unit -> PhysicsEngine + default this.MakePhysicsEngine2d () = + AetherPhysicsEngine.make (Constants.Physics.GravityDefault * Constants.Engine.Meter2d) + + /// Make a 2D physics engine render context for the engine to use for the current frame. + abstract MakePhysicsEngine2dRenderContext : + segments : Dictionary -> + circles : Dictionary -> + eyeBounds : Box2 -> + PhysicsEngineRenderContext + default this.MakePhysicsEngine2dRenderContext segments circles eyeBounds = + { new AetherPhysicsEngineRenderContext with + override this.DrawLine (start : Vector2, stop : Vector2, color) = + match segments.TryGetValue color with + | (true, segmentList) -> segmentList.Add (start, stop) + | (false, _) -> segments.Add (color, List [struct (start, stop)]) + override this.DrawCircle (center : Vector2, radius, color) = + match circles.TryGetValue struct (color, radius) with + | (true, circleList) -> circleList.Add center + | (false, _) -> circles.Add (struct (color, radius), List [center]) + override _.EyeBounds = eyeBounds } + /// A call-back at the beginning of each frame. abstract PreProcess : world : World -> unit default this.PreProcess _ = () diff --git a/Projects/Blaze Vector ImSim/Assets.fs b/Projects/Blaze Vector ImSim/Assets.fs index 3798507f50..79453ac135 100644 --- a/Projects/Blaze Vector ImSim/Assets.fs +++ b/Projects/Blaze Vector ImSim/Assets.fs @@ -12,7 +12,7 @@ module Assets = module Gui = let PackageName = "Gui" - let MachinerySong = { FadeInTime = GameTime.zero; FadeOutTime = Constants.Audio.FadeOutTimeDefault; StartTime = GameTime.zero; RepeatLimitOpt = None; Volume = 1.0f; Song = asset PackageName "Machinery" } + let MachinerySong = { SongDescriptor.defaultDescriptor with Song = asset PackageName "Machinery" } let TitleGroupFilePath = "Assets/Gui/Title.nugroup" let CreditsGroupFilePath = "Assets/Gui/Credits.nugroup" @@ -30,7 +30,7 @@ module Assets = let ShotSound = asset PackageName "Shot" let JumpSound = asset PackageName "Jump" let DeathSound = asset PackageName "Death" - let DeadBlazeSong = { FadeInTime = GameTime.zero; FadeOutTime = Constants.Audio.FadeOutTimeDefault; StartTime = GameTime.zero; RepeatLimitOpt = None; Volume = 2.0f; Song = asset PackageName "DeadBlaze" } + let DeadBlazeSong = { SongDescriptor.defaultDescriptor with Volume = 2.0f; Song = asset PackageName "DeadBlaze" } let Section0FilePath = "Assets/Gameplay/Section0.nugroup" let Section1FilePath = "Assets/Gameplay/Section1.nugroup" let Section2FilePath = "Assets/Gameplay/Section2.nugroup" diff --git a/Projects/Blaze Vector ImSim/Assets/Default/AnimatedModelIcon.png b/Projects/Blaze Vector ImSim/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Projects/Blaze Vector ImSim/Assets/Default/AnimatedModelIcon.png differ diff --git a/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Projects/Blaze Vector ImSim/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Blaze Vector ImSim/Assets/Default/RawIcon.png b/Projects/Blaze Vector ImSim/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Projects/Blaze Vector ImSim/Assets/Default/RawIcon.png differ diff --git a/Projects/Blaze Vector ImSim/Assets/Default/SongIcon.png b/Projects/Blaze Vector ImSim/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Projects/Blaze Vector ImSim/Assets/Default/SongIcon.png differ diff --git a/Projects/Blaze Vector ImSim/Assets/Default/SoundIcon.png b/Projects/Blaze Vector ImSim/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Projects/Blaze Vector ImSim/Assets/Default/SoundIcon.png differ diff --git a/Projects/Blaze Vector ImSim/Assets/Default/SpineSkeletonIcon.png b/Projects/Blaze Vector ImSim/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Projects/Blaze Vector ImSim/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Projects/Blaze Vector ImSim/Assets/Default/StaticModelIcon.png b/Projects/Blaze Vector ImSim/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Projects/Blaze Vector ImSim/Assets/Default/StaticModelIcon.png differ diff --git a/Projects/Blaze Vector ImSim/Assets/Default/TileMapIcon.png b/Projects/Blaze Vector ImSim/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Projects/Blaze Vector ImSim/Assets/Default/TileMapIcon.png differ diff --git a/Projects/Blaze Vector ImSim/Enemy.fs b/Projects/Blaze Vector ImSim/Enemy.fs index a4d6487715..ba81536151 100644 --- a/Projects/Blaze Vector ImSim/Enemy.fs +++ b/Projects/Blaze Vector ImSim/Enemy.fs @@ -54,9 +54,9 @@ type EnemyDispatcher () = penetrations if Seq.notEmpty hits then entity.Health.Map dec world - World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.HitSound world + World.playSound 0.0f 0.5f 1.0f Assets.Gameplay.HitSound world // process death if entity.GetHealth world <= 0 then World.publish () entity.DeathEvent entity world - World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.ExplosionSound world \ No newline at end of file + World.playSound 0.0f 0.5f 1.0f Assets.Gameplay.ExplosionSound world \ No newline at end of file diff --git a/Projects/Blaze Vector ImSim/Gameplay.fs b/Projects/Blaze Vector ImSim/Gameplay.fs index 224171fd39..8cef813784 100644 --- a/Projects/Blaze Vector ImSim/Gameplay.fs +++ b/Projects/Blaze Vector ImSim/Gameplay.fs @@ -69,8 +69,7 @@ type GameplayDispatcher () = // declare player World.doEntity "Player" [Entity.Position |= v3 -390.0f -50.0f 0.0f - Entity.Elevation .= 1.0f] - world + Entity.Elevation .= 1.0f] world let player = world.DeclaredEntity // process scoring @@ -83,7 +82,7 @@ type GameplayDispatcher () = // process player death if World.doSubscriptionAny "Death" player.DeathEvent world then match screen.GetGameplayState world with - | Playing -> World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.DeathSound world + | Playing -> World.playSound 0.0f 0.0f 1.0f Assets.Gameplay.DeathSound world | Quit -> () // already in quit state, so no need to play sound again screen.SetGameplayState Quit world diff --git a/Projects/Blaze Vector ImSim/Player.fs b/Projects/Blaze Vector ImSim/Player.fs index 31b65e934c..3cae823c20 100644 --- a/Projects/Blaze Vector ImSim/Player.fs +++ b/Projects/Blaze Vector ImSim/Player.fs @@ -65,7 +65,7 @@ type PlayerDispatcher () = bullet.SetElevation (entity.GetElevation world) world bullet.SetCreationTime world.UpdateTime world World.applyBodyLinearImpulse (v3 Constants.Gameplay.BulletImpulse 0.0f 0.0f) None (bullet.GetBodyId world) world - World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.ShotSound world + World.playSound 0.0f 0.0f 1.0f Assets.Gameplay.ShotSound world // process jumping if world.Advancing && @@ -74,7 +74,7 @@ type PlayerDispatcher () = World.isKeyboardKeyPressed KeyboardKey.Space world then entity.SetLastTimeJump world.UpdateTime world World.applyBodyLinearImpulse (v3 0.0f Constants.Gameplay.PlayerJumpForce 0.0f) None (entity.GetBodyId world) world - World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.JumpSound world + World.playSound 0.0f -0.5f 1.0f Assets.Gameplay.JumpSound world // process death if fallen then diff --git a/Projects/Blaze Vector Mmcc/Assets/Default/AnimatedModelIcon.png b/Projects/Blaze Vector Mmcc/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Projects/Blaze Vector Mmcc/Assets/Default/AnimatedModelIcon.png differ diff --git a/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Projects/Blaze Vector Mmcc/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Blaze Vector Mmcc/Assets/Default/RawIcon.png b/Projects/Blaze Vector Mmcc/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Projects/Blaze Vector Mmcc/Assets/Default/RawIcon.png differ diff --git a/Projects/Blaze Vector Mmcc/Assets/Default/SongIcon.png b/Projects/Blaze Vector Mmcc/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Projects/Blaze Vector Mmcc/Assets/Default/SongIcon.png differ diff --git a/Projects/Blaze Vector Mmcc/Assets/Default/SoundIcon.png b/Projects/Blaze Vector Mmcc/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Projects/Blaze Vector Mmcc/Assets/Default/SoundIcon.png differ diff --git a/Projects/Blaze Vector Mmcc/Assets/Default/SpineSkeletonIcon.png b/Projects/Blaze Vector Mmcc/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Projects/Blaze Vector Mmcc/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Projects/Blaze Vector Mmcc/Assets/Default/StaticModelIcon.png b/Projects/Blaze Vector Mmcc/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Projects/Blaze Vector Mmcc/Assets/Default/StaticModelIcon.png differ diff --git a/Projects/Blaze Vector Mmcc/Assets/Default/TileMapIcon.png b/Projects/Blaze Vector Mmcc/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Projects/Blaze Vector Mmcc/Assets/Default/TileMapIcon.png differ diff --git a/Projects/Blaze Vector Mmcc/Enemy.fs b/Projects/Blaze Vector Mmcc/Enemy.fs index 52781332d9..f92dbf70af 100644 --- a/Projects/Blaze Vector Mmcc/Enemy.fs +++ b/Projects/Blaze Vector Mmcc/Enemy.fs @@ -71,6 +71,6 @@ type EnemyDispatcher () = if enemy.Health <= 0 then World.publish () entity.DeathEvent entity world World.destroyEntity entity world - World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.ExplosionSound world + World.playSound 0.0f 0.5f 1.0f Assets.Gameplay.ExplosionSound world | Hit -> - World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.HitSound world \ No newline at end of file + World.playSound 0.0f 0.5f 1.0f Assets.Gameplay.HitSound world \ No newline at end of file diff --git a/Projects/Blaze Vector Mmcc/Player.fs b/Projects/Blaze Vector Mmcc/Player.fs index 8025924b16..05027c8916 100644 --- a/Projects/Blaze Vector Mmcc/Player.fs +++ b/Projects/Blaze Vector Mmcc/Player.fs @@ -113,15 +113,15 @@ type PlayerDispatcher () = | Jump -> World.applyBodyLinearImpulse (v3 0.0f Constants.Gameplay.PlayerJumpForce 0.0f) None (entity.GetBodyId world) world - World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.JumpSound world + World.playSound 0.0f -0.5f 1.0f Assets.Gameplay.JumpSound world | Shoot -> let bullet = World.createEntity None NoOverlay None entity.Group world // OPTIMIZATION: NoOverlay to avoid reflection. bullet.SetPosition (entity.GetPosition world + v3 24.0f 1.0f 0.0f) world bullet.SetElevation (entity.GetElevation world) world World.applyBodyLinearImpulse (v3 Constants.Gameplay.BulletImpulse 0.0f 0.0f) None (bullet.GetBodyId world) world - World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.ShotSound world + World.playSound 0.0f 0.0f 1.0f Assets.Gameplay.ShotSound world | Die -> World.publish () entity.DeathEvent entity world - World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.DeathSound world \ No newline at end of file + World.playSound 0.0f 0.0f 1.0f Assets.Gameplay.DeathSound world \ No newline at end of file diff --git a/Projects/Breakout ImSim/Assets/Default/AnimatedModelIcon.png b/Projects/Breakout ImSim/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Projects/Breakout ImSim/Assets/Default/AnimatedModelIcon.png differ diff --git a/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Projects/Breakout ImSim/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Breakout ImSim/Assets/Default/RawIcon.png b/Projects/Breakout ImSim/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Projects/Breakout ImSim/Assets/Default/RawIcon.png differ diff --git a/Projects/Breakout ImSim/Assets/Default/SongIcon.png b/Projects/Breakout ImSim/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Projects/Breakout ImSim/Assets/Default/SongIcon.png differ diff --git a/Projects/Breakout ImSim/Assets/Default/SoundIcon.png b/Projects/Breakout ImSim/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Projects/Breakout ImSim/Assets/Default/SoundIcon.png differ diff --git a/Projects/Breakout ImSim/Assets/Default/SpineSkeletonIcon.png b/Projects/Breakout ImSim/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Projects/Breakout ImSim/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Projects/Breakout ImSim/Assets/Default/StaticModelIcon.png b/Projects/Breakout ImSim/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Projects/Breakout ImSim/Assets/Default/StaticModelIcon.png differ diff --git a/Projects/Breakout ImSim/Assets/Default/TileMapIcon.png b/Projects/Breakout ImSim/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Projects/Breakout ImSim/Assets/Default/TileMapIcon.png differ diff --git a/Projects/Breakout ImSim/Gameplay.fs b/Projects/Breakout ImSim/Gameplay.fs index 700bced790..5e3b9eb89a 100644 --- a/Projects/Breakout ImSim/Gameplay.fs +++ b/Projects/Breakout ImSim/Gameplay.fs @@ -150,7 +150,7 @@ type GameplayDispatcher () = // paddle collision let bounce = (ball.GetPosition world - paddle.GetPosition world).Normalized * BallSpeed World.setBodyLinearVelocity bounce ballBodyId world - World.playSound 1.0f Assets.Default.Sound world + World.playSound 0.0f 0.0f 1.0f Assets.Default.Sound world else @@ -161,7 +161,7 @@ type GameplayDispatcher () = World.setBodyLinearVelocity bounce ballBodyId world screen.Score.Map ((+) 100) world screen.Bricks.Map (Map.remove penetrateeId.BodySource.Name) world - World.playSound 1.0f Assets.Default.Sound world + World.playSound 0.0f 0.0f 1.0f Assets.Default.Sound world // wall collision | (false, _) -> @@ -173,7 +173,7 @@ type GameplayDispatcher () = let velocity = ball.GetLinearVelocity world let bounce = velocity - 2.0f * Vector3.Dot (velocity, normal) * normal World.setBodyLinearVelocity bounce ballBodyId world - World.playSound 1.0f Assets.Default.Sound world + World.playSound 0.0f 0.0f 1.0f Assets.Default.Sound world | _ -> () diff --git a/Projects/Breakout Mmcc/Assets/Default/AnimatedModelIcon.png b/Projects/Breakout Mmcc/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Projects/Breakout Mmcc/Assets/Default/AnimatedModelIcon.png differ diff --git a/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Projects/Breakout Mmcc/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Breakout Mmcc/Assets/Default/RawIcon.png b/Projects/Breakout Mmcc/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Projects/Breakout Mmcc/Assets/Default/RawIcon.png differ diff --git a/Projects/Breakout Mmcc/Assets/Default/SongIcon.png b/Projects/Breakout Mmcc/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Projects/Breakout Mmcc/Assets/Default/SongIcon.png differ diff --git a/Projects/Breakout Mmcc/Assets/Default/SoundIcon.png b/Projects/Breakout Mmcc/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Projects/Breakout Mmcc/Assets/Default/SoundIcon.png differ diff --git a/Projects/Breakout Mmcc/Assets/Default/SpineSkeletonIcon.png b/Projects/Breakout Mmcc/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Projects/Breakout Mmcc/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Projects/Breakout Mmcc/Assets/Default/StaticModelIcon.png b/Projects/Breakout Mmcc/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Projects/Breakout Mmcc/Assets/Default/StaticModelIcon.png differ diff --git a/Projects/Breakout Mmcc/Assets/Default/TileMapIcon.png b/Projects/Breakout Mmcc/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Projects/Breakout Mmcc/Assets/Default/TileMapIcon.png differ diff --git a/Projects/Breakout Mmcc/Gameplay.fs b/Projects/Breakout Mmcc/Gameplay.fs index 11eb457a58..b645c3179e 100644 --- a/Projects/Breakout Mmcc/Gameplay.fs +++ b/Projects/Breakout Mmcc/Gameplay.fs @@ -112,12 +112,12 @@ type [] Gameplay = let ball = if ball.PositionNext.X <= -160.0f || ball.PositionNext.X >= 160.0f then - World.playSound 1.0f Assets.Default.Sound world + World.playSound 0.0f 0.0f 1.0f Assets.Default.Sound world { ball with Direction = ball.Direction.MapX negate } else ball let ball = if ball.PositionNext.Y >= 172.0f then - World.playSound 1.0f Assets.Default.Sound world + World.playSound 0.0f 0.0f 1.0f Assets.Default.Sound world { ball with Direction = ball.Direction.MapY negate } else ball { gameplay with Ball = ball } @@ -129,7 +129,7 @@ type [] Gameplay = let ball = let perimeter = box3 (paddle.Position - paddle.Size * 0.5f) paddle.Size if perimeter.Intersects ball.PositionNext then - World.playSound 1.0f Assets.Default.Sound world + World.playSound 0.0f 0.0f 1.0f Assets.Default.Sound world { ball with Direction = (ball.Position - paddle.Position).Normalized } else ball { gameplay with Ball = ball } @@ -144,7 +144,7 @@ type [] Gameplay = gameplay.Bricks let ball = if Map.notEmpty bricksIntersected then - World.playSound 1.0f Assets.Default.Sound world + World.playSound 0.0f 0.0f 1.0f Assets.Default.Sound world let brick = Seq.head bricksIntersected.Values { ball with Direction = (ball.Position - brick.Position).Normalized } else ball diff --git a/Projects/Jump Box/Assets/Default/AnimatedModelIcon.png b/Projects/Jump Box/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Projects/Jump Box/Assets/Default/AnimatedModelIcon.png differ diff --git a/Projects/Jump Box/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Projects/Jump Box/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Projects/Jump Box/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Projects/Jump Box/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Projects/Jump Box/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Projects/Jump Box/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Projects/Jump Box/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Projects/Jump Box/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Projects/Jump Box/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Projects/Jump Box/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Projects/Jump Box/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Projects/Jump Box/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Jump Box/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Projects/Jump Box/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Projects/Jump Box/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Projects/Jump Box/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Jump Box/Assets/Default/RawIcon.png b/Projects/Jump Box/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Projects/Jump Box/Assets/Default/RawIcon.png differ diff --git a/Projects/Jump Box/Assets/Default/SongIcon.png b/Projects/Jump Box/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Projects/Jump Box/Assets/Default/SongIcon.png differ diff --git a/Projects/Jump Box/Assets/Default/SoundIcon.png b/Projects/Jump Box/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Projects/Jump Box/Assets/Default/SoundIcon.png differ diff --git a/Projects/Jump Box/Assets/Default/SpineSkeletonIcon.png b/Projects/Jump Box/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Projects/Jump Box/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Projects/Jump Box/Assets/Default/StaticModelIcon.png b/Projects/Jump Box/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Projects/Jump Box/Assets/Default/StaticModelIcon.png differ diff --git a/Projects/Jump Box/Assets/Default/TileMapIcon.png b/Projects/Jump Box/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Projects/Jump Box/Assets/Default/TileMapIcon.png differ diff --git a/Projects/Jump Box/JumpBox.fs b/Projects/Jump Box/JumpBox.fs index 0ae21a919d..59dbf2d4aa 100644 --- a/Projects/Jump Box/JumpBox.fs +++ b/Projects/Jump Box/JumpBox.fs @@ -31,7 +31,7 @@ type JumpBoxDispatcher () = World.doBlock2d "Block" [Entity.Position .= v3 128.0f -64.0f 0.0f] world |> ignore // declare a box and then handle its body interactions for the frame - let (boxBodyId, results) = World.doBox2d "Box" [Entity.Position .= v3 128.0f 64.0f 0.0f] world + let (boxBodyId, results) = World.doBox2d "Box" [Entity.Position |= v3 128.0f 64.0f 0.0f] world for result in results do match result with | BodyPenetrationData _ -> game.Collisions.Map inc world diff --git a/Projects/Metrics/Assets/Default/AnimatedModelIcon.png b/Projects/Metrics/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Projects/Metrics/Assets/Default/AnimatedModelIcon.png differ diff --git a/Projects/Metrics/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Projects/Metrics/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Projects/Metrics/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Projects/Metrics/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Projects/Metrics/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Projects/Metrics/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Projects/Metrics/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Projects/Metrics/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Projects/Metrics/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Projects/Metrics/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Projects/Metrics/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Projects/Metrics/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Metrics/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Projects/Metrics/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Projects/Metrics/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Projects/Metrics/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Metrics/Assets/Default/RawIcon.png b/Projects/Metrics/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Projects/Metrics/Assets/Default/RawIcon.png differ diff --git a/Projects/Metrics/Assets/Default/SongIcon.png b/Projects/Metrics/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Projects/Metrics/Assets/Default/SongIcon.png differ diff --git a/Projects/Metrics/Assets/Default/SoundIcon.png b/Projects/Metrics/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Projects/Metrics/Assets/Default/SoundIcon.png differ diff --git a/Projects/Metrics/Assets/Default/SpineSkeletonIcon.png b/Projects/Metrics/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Projects/Metrics/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Projects/Metrics/Assets/Default/StaticModelIcon.png b/Projects/Metrics/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Projects/Metrics/Assets/Default/StaticModelIcon.png differ diff --git a/Projects/Metrics/Assets/Default/TileMapIcon.png b/Projects/Metrics/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Projects/Metrics/Assets/Default/TileMapIcon.png differ diff --git a/Projects/Metrics/Program.fs b/Projects/Metrics/Program.fs index 6b94bcec83..6b252faebe 100644 --- a/Projects/Metrics/Program.fs +++ b/Projects/Metrics/Program.fs @@ -47,7 +47,7 @@ type MmccGameMessage = interface Message type MmccGameDispatcher () = - inherit GameDispatcher (Intss.init 82) // 6,724 entities + inherit GameDispatcher (Intss.init 100) // 10,000 entities override this.Definitions (_, _) = [Game.UpdateEvent => Inc] @@ -63,7 +63,7 @@ type MmccGameDispatcher () = [for (j, int) in ints.Ints.Pairs' do Content.entity (string j) [Entity.Presence == Omnipresent - Entity.Position == v3 (single i * 4.25f - 245.0f) (single j * 2.25f - 125.0f) -250.0f + Entity.Position == v3 (single i * 5.0f - 245.0f) (single j * 2.75f - 135.0f) -250.0f Entity.Scale := v3Dup (single (int % 10)) * 0.5f]] Content.group "Other" [] [Content.skyBox "SkyBox" [] @@ -78,10 +78,10 @@ type MyGameDispatcher () = #if IMSIM inherit GameDispatcherImSim () - static let Positions = // 7,500 entities + static let Positions = // 10,000 entities [|for i in 0 .. dec 50 do for j in 0 .. dec 50 do - for k in 0 .. dec 3 do + for k in 0 .. dec 4 do yield v3 (single i * 0.5f) (single j * 0.5f) (single k * 0.5f)|] override this.Process (_, world) = diff --git a/Projects/Nelmish/Assets/Default/AnimatedModelIcon.png b/Projects/Nelmish/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Projects/Nelmish/Assets/Default/AnimatedModelIcon.png differ diff --git a/Projects/Nelmish/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Projects/Nelmish/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Projects/Nelmish/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Projects/Nelmish/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Projects/Nelmish/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Projects/Nelmish/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Projects/Nelmish/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Projects/Nelmish/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Projects/Nelmish/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Projects/Nelmish/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Projects/Nelmish/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Projects/Nelmish/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Nelmish/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Projects/Nelmish/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Projects/Nelmish/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Projects/Nelmish/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Nelmish/Assets/Default/RawIcon.png b/Projects/Nelmish/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Projects/Nelmish/Assets/Default/RawIcon.png differ diff --git a/Projects/Nelmish/Assets/Default/SongIcon.png b/Projects/Nelmish/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Projects/Nelmish/Assets/Default/SongIcon.png differ diff --git a/Projects/Nelmish/Assets/Default/SoundIcon.png b/Projects/Nelmish/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Projects/Nelmish/Assets/Default/SoundIcon.png differ diff --git a/Projects/Nelmish/Assets/Default/SpineSkeletonIcon.png b/Projects/Nelmish/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Projects/Nelmish/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Projects/Nelmish/Assets/Default/StaticModelIcon.png b/Projects/Nelmish/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Projects/Nelmish/Assets/Default/StaticModelIcon.png differ diff --git a/Projects/Nelmish/Assets/Default/TileMapIcon.png b/Projects/Nelmish/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Projects/Nelmish/Assets/Default/TileMapIcon.png differ diff --git a/Projects/Sand Box 2d/Assets/Default/AnimatedModelIcon.png b/Projects/Sand Box 2d/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Projects/Sand Box 2d/Assets/Default/AnimatedModelIcon.png differ diff --git a/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Projects/Sand Box 2d/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Sand Box 2d/Assets/Default/RawIcon.png b/Projects/Sand Box 2d/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Projects/Sand Box 2d/Assets/Default/RawIcon.png differ diff --git a/Projects/Sand Box 2d/Assets/Default/SongIcon.png b/Projects/Sand Box 2d/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Projects/Sand Box 2d/Assets/Default/SongIcon.png differ diff --git a/Projects/Sand Box 2d/Assets/Default/SoundIcon.png b/Projects/Sand Box 2d/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Projects/Sand Box 2d/Assets/Default/SoundIcon.png differ diff --git a/Projects/Sand Box 2d/Assets/Default/SpineSkeletonIcon.png b/Projects/Sand Box 2d/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Projects/Sand Box 2d/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Projects/Sand Box 2d/Assets/Default/StaticModelIcon.png b/Projects/Sand Box 2d/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Projects/Sand Box 2d/Assets/Default/StaticModelIcon.png differ diff --git a/Projects/Sand Box 2d/Assets/Default/TileMapIcon.png b/Projects/Sand Box 2d/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Projects/Sand Box 2d/Assets/Default/TileMapIcon.png differ diff --git a/Projects/Sand Box 2d/FluidSim.fs b/Projects/Sand Box 2d/FluidSim.fs index 29fdbb11a3..16cb440bfe 100644 --- a/Projects/Sand Box 2d/FluidSim.fs +++ b/Projects/Sand Box 2d/FluidSim.fs @@ -260,7 +260,7 @@ type FluidSimDispatcher () = paddle.SetBodyType Kinematic world paddle.SetLinearVelocity (v3 50f 0f 0f) world coroutine world.Launcher { - do! Coroutine.sleep (GameTime.ofSeconds 10f) + do! Coroutine.sleep (GameTime.ofSeconds 10) World.destroyEntity paddle world } // switch screen button diff --git a/Projects/Sand Box 2d/ToyBox.fs b/Projects/Sand Box 2d/ToyBox.fs index e60fcb09eb..de5e8603b4 100644 --- a/Projects/Sand Box 2d/ToyBox.fs +++ b/Projects/Sand Box 2d/ToyBox.fs @@ -327,8 +327,8 @@ type ToyBoxDispatcher () = WeldJoint (a, b, a.Position, b.Position, true) } Entity.BodyJointTarget .= anchor.EntityAddress Entity.BodyJointTarget2 .= blade.EntityAddress - Entity.CollideConnected .= false // When the two blades are set to collide, the + shape would deform on drag - ] world |> ignore + Entity.CollideConnected .= false] // when the two blades are set to collide, the + shape would deform on drag + world |> ignore // end anchor blade declaration World.endEntity world @@ -360,8 +360,7 @@ type ToyBoxDispatcher () = Entity.BodyJointTarget .= Address.makeFromString $"^/{linkTo}" Entity.BodyJointTarget2 .= Address.makeFromString $"^/{newLeg}" Entity.CollideConnected .= false // rotation movement would be limited if the upper leg collides with center - Entity.MountOpt .= None] - world |> ignore + Entity.MountOpt .= None] world |> ignore let isExtended = world.ClockTime % 10f >= 5f let twoBodyJoint = AetherBodyJoint { CreateBodyJoint = fun _ _ a b -> @@ -505,8 +504,8 @@ type ToyBoxDispatcher () = [Entity.BodyJoint |= twoBodyBodyJoint Entity.BodyJointTarget .= Address.makeFromString $"^/{n1}" Entity.BodyJointTarget2 .= Address.makeFromString $"^/{n2}" - Entity.CollideConnected .= true // Each box linked should collide with each other - ] world |> ignore + Entity.CollideConnected .= true] // each box linked should collide with each other + world |> ignore // declare distance joint linkage between contour boxes and center ball for stabilizing the shape for n in boxNames do @@ -520,8 +519,7 @@ type ToyBoxDispatcher () = // specified by starting with the parent link denoted by "^", then accessing the sub-entity using "/". [Entity.BodyJoint |= twoBodyJoint Entity.BodyJointTarget .= center.EntityAddress - Entity.BodyJointTarget2 .= Address.makeFromString $"^/{n}" - ] world |> ignore + Entity.BodyJointTarget2 .= Address.makeFromString $"^/{n}"] world |> ignore // end center ball declaration World.endEntity world @@ -623,7 +621,7 @@ type ToyBoxDispatcher () = // declare motor World.doBodyJoint2d $"{name} Motor" [Entity.BodyJoint |= AetherBodyJoint { CreateBodyJoint = fun _ _ a b -> - // specifying a motor for the revolute joint rotates the first body with a constant angular velocity. + // specifying a motor for the revolute joint rotates the first body with a constant angular velocity RevoluteJoint (a, b, b.Position, true, MotorEnabled = true, MotorSpeed = 2f, MaxMotorTorque = 400f) } Entity.BodyJointTarget .= wheel.EntityAddress Entity.BodyJointTarget2 .= chassis.EntityAddress @@ -755,17 +753,17 @@ type ToyBoxDispatcher () = ("^", defaultGravity.Transform (Quaternion.CreateFromAngle2d MathF.PI)) ("<", defaultGravity.Transform (Quaternion.CreateFromAngle2d -MathF.PI_OVER_2))] |> List.randomShuffle - |> List.cons ("v", defaultGravity) // Always start with the default down gravity + |> List.cons ("v", defaultGravity) // always start with the default down gravity static let generateAvatarGravities (world : World) = let defaultGravity = World.getGravityDefault2d world - [(">", Gravity (defaultGravity.Transform (Quaternion.CreateFromAngle2d MathF.PI_OVER_2))) - ("0", Gravity v3Zero) - ("^", Gravity (defaultGravity.Transform (Quaternion.CreateFromAngle2d MathF.PI))) - ("<", Gravity (defaultGravity.Transform (Quaternion.CreateFromAngle2d -MathF.PI_OVER_2))) - ("v", Gravity defaultGravity)] + [(">", GravityOverride (defaultGravity.Transform (Quaternion.CreateFromAngle2d MathF.PI_OVER_2))) + ("0", GravityOverride v3Zero) + ("^", GravityOverride (defaultGravity.Transform (Quaternion.CreateFromAngle2d MathF.PI))) + ("<", GravityOverride (defaultGravity.Transform (Quaternion.CreateFromAngle2d -MathF.PI_OVER_2))) + ("v", GravityOverride defaultGravity)] |> List.randomShuffle - |> List.cons ("World", GravityWorld) // Always start with GravityDefault + |> List.cons ("World", GravityWorld) // always start with GravityWorld // here we define default property values static member Properties = diff --git a/Projects/Terra Firma/Assets/Default/AnimatedModelIcon.png b/Projects/Terra Firma/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Projects/Terra Firma/Assets/Default/AnimatedModelIcon.png differ diff --git a/Projects/Terra Firma/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Projects/Terra Firma/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Projects/Terra Firma/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Projects/Terra Firma/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Projects/Terra Firma/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Projects/Terra Firma/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Projects/Terra Firma/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Projects/Terra Firma/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Projects/Terra Firma/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Projects/Terra Firma/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Projects/Terra Firma/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Projects/Terra Firma/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Terra Firma/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Projects/Terra Firma/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Projects/Terra Firma/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Projects/Terra Firma/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Terra Firma/Assets/Default/RawIcon.png b/Projects/Terra Firma/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Projects/Terra Firma/Assets/Default/RawIcon.png differ diff --git a/Projects/Terra Firma/Assets/Default/SongIcon.png b/Projects/Terra Firma/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Projects/Terra Firma/Assets/Default/SongIcon.png differ diff --git a/Projects/Terra Firma/Assets/Default/SoundIcon.png b/Projects/Terra Firma/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Projects/Terra Firma/Assets/Default/SoundIcon.png differ diff --git a/Projects/Terra Firma/Assets/Default/SpineSkeletonIcon.png b/Projects/Terra Firma/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Projects/Terra Firma/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Projects/Terra Firma/Assets/Default/StaticModelIcon.png b/Projects/Terra Firma/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Projects/Terra Firma/Assets/Default/StaticModelIcon.png differ diff --git a/Projects/Terra Firma/Assets/Default/TileMapIcon.png b/Projects/Terra Firma/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Projects/Terra Firma/Assets/Default/TileMapIcon.png differ diff --git a/Projects/Terra Firma/Assets/Gameplay/Scene.nugroup b/Projects/Terra Firma/Assets/Gameplay/Scene.nugroup index 618cfcc7ba..aa167943e1 100644 --- a/Projects/Terra Firma/Assets/Gameplay/Scene.nugroup +++ b/Projects/Terra Firma/Assets/Gameplay/Scene.nugroup @@ -171,7 +171,6 @@ [FinenessOffsetOpt None] [ScatterTypeOpt None]]] [Name Ground] - [NavShape StaticModelNavShape] [Order 3559661103553] [Position [-2 1.59 -4.5]] [PositionLocal [-2 -0.05 -4.5]] @@ -234,7 +233,6 @@ [[Gameplay House] Concave None None]]] [MountOpt [Some ^]] [Name House] - [NavShape StaticModelNavShape] [Offset [0 0.3668699 0]] [Order 1645309435779] [Position [-0.5 1.64 -4.7]] @@ -309,7 +307,6 @@ [OpaqueDistanceOpt None]]] [MountOpt [Some ^]] [Name House2] - [NavShape StaticModelNavShape] [Offset [0 0.6676477 0]] [Order 613197939149] [Position [-6.7 1.64 2.6]] @@ -614,7 +611,6 @@ [[Gameplay Barrier] Convex None None]]] [MountOpt [Some ^]] [Name Barrier] - [NavShape StaticModelNavShape] [Offset [0.110984206 0.46470478 0.8669058]] [Order 1645316460604] [Position [-8.2 1.6 7]] @@ -1254,7 +1250,6 @@ [TwoSidedOpt None] [ClippedOpt None]]] [Name Container] - [NavShape StaticModelNavShape] [Offset [1.1920929E-07 -0.07810056 -2.3841858E-07]] [Order 3559665458680] [Position [0 3 -14.8]] @@ -1344,7 +1339,6 @@ [RefractiveIndexOpt None]]] [MountOpt [Some ^]] [Name Ground] - [NavShape StaticModelNavShape] [Position [-2 1.59 -4.5]] [PositionLocal [-2 -0.05 -4.5]] [Scale [26.9 0.1 30.4]] @@ -1408,7 +1402,6 @@ [[Gameplay House] Concave None None]]] [MountOpt [Some ^]] [Name House] - [NavShape StaticModelNavShape] [Offset [0 0.3668699 0]] [Order 1645309435779] [Position [-0.5 1.64 -4.7]] @@ -1485,7 +1478,6 @@ [OpaqueDistanceOpt None]]] [MountOpt [Some ^]] [Name House2] - [NavShape StaticModelNavShape] [Offset [0 0.6676477 0]] [Order 613197939149] [Position [-6.7 1.64 2.6]] @@ -1806,7 +1798,6 @@ [[Gameplay Barrier] Convex None None]]] [MountOpt [Some ^]] [Name Barrier] - [NavShape StaticModelNavShape] [Offset [0.110984206 0.46470478 0.8669058]] [Order 1645316460604] [Position [-8.2 1.6 7]] @@ -2467,7 +2458,6 @@ [ClippedOpt None]]] [MountOpt [Some ^]] [Name Container] - [NavShape StaticModelNavShape] [Offset [1.1920929E-07 -0.07810056 -2.3841858E-07]] [Position [0 3 -14.8]] [PositionLocal [0 1.36 -14.8]] @@ -2562,7 +2552,6 @@ [RefractiveIndexOpt None]]] [MountOpt [Some ^]] [Name Ground] - [NavShape StaticModelNavShape] [Position [-3.7000003 1.25 25.5]] [PositionLocal [-2 -0.05 -4.5]] [Rotation [0 -0.70710677 0 0.70710677]] @@ -3520,7 +3509,6 @@ [ClippedOpt None]]] [MountOpt [Some ^]] [Name Container] - [NavShape StaticModelNavShape] [Offset [1.1920929E-07 -0.0909127 -2.3841858E-07]] [Position [6.5999994 2.6599998 27.5]] [PositionLocal [0 1.36 -14.8]] @@ -3601,7 +3589,6 @@ [RefractiveIndexOpt None]]] [MountOpt [Some ^]] [Name Ground] - [NavShape StaticModelNavShape] [Position [26.7 2.05 27.2]] [PositionLocal [-2 -0.05 -4.5]] [Rotation [0 -1 0 -4.371139E-08]] @@ -4559,7 +4546,6 @@ [ClippedOpt None]]] [MountOpt [Some ^]] [Name Container] - [NavShape StaticModelNavShape] [Offset [1.1920929E-07 -0.07810056 -2.3841858E-07]] [Position [24.699999 3.46 37.5]] [PositionLocal [0 1.36 -14.8]] @@ -4640,7 +4626,6 @@ [RefractiveIndexOpt None]]] [MountOpt [Some ^]] [Name Ground] - [NavShape StaticModelNavShape] [Position [26.8 2.05 -4.5]] [PositionLocal [-2 -0.05 -4.5]] [Rotation [0 1 -0 -4.371139E-08]] @@ -5598,7 +5583,6 @@ [ClippedOpt None]]] [MountOpt [Some ^]] [Name Container] - [NavShape StaticModelNavShape] [Offset [1.1920929E-07 -0.07810056 -2.3841858E-07]] [Position [24.800001 3.46 5.8]] [PositionLocal [0 1.36 -14.8]] diff --git a/Projects/Terra Firma/Character.fs b/Projects/Terra Firma/Character.fs index eee6fc7054..2205e2f822 100644 --- a/Projects/Terra Firma/Character.fs +++ b/Projects/Terra Firma/Character.fs @@ -121,8 +121,8 @@ type CharacterDispatcher () = | AttackState attack -> let localTime = world.UpdateTime - attack.AttackTime match localTime with - | 7L -> World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.SlashSound world - | 67L -> World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.Slash2Sound world + | 7L -> World.playSound 0.0f 0.0f 1.0f Assets.Gameplay.SlashSound world + | 67L -> World.playSound 0.0f 0.0f 1.0f Assets.Gameplay.Slash2Sound world | _ -> () let (animationTime, animationName) = if localTime <= 55L @@ -234,7 +234,7 @@ type CharacterDispatcher () = let turnVelocity = (if World.isKeyboardKeyDown KeyboardKey.Right world then -turnSpeed else 0.0f) + (if World.isKeyboardKeyDown KeyboardKey.Left world then turnSpeed else 0.0f) - let rotation = if turnVelocity <> 0.0f then rotation * Quaternion.CreateFromAxisAngle (v3Up, turnVelocity * world.GameDelta.Seconds) else rotation + let rotation = if turnVelocity <> 0.0f then rotation * Quaternion.CreateFromAxisAngle (v3Up, turnVelocity * world.GameDelta.SecondsF) else rotation // apply changes entity.SetLinearVelocity (walkVelocity.WithY 0.0f + entity.GetLinearVelocity world * v3Up) world diff --git a/Projects/Terra Firma/Gameplay.fs b/Projects/Terra Firma/Gameplay.fs index 84ba6203d4..7f21efa97c 100644 --- a/Projects/Terra Firma/Gameplay.fs +++ b/Projects/Terra Firma/Gameplay.fs @@ -44,8 +44,10 @@ type GameplayDispatcher () = // begin scene declaration, processing nav sync at end of frame since optimized representations like // frozen entities won't have their nav info registered until then - World.beginGroupFromFile Simulants.GameplayScene.Name "Assets/Gameplay/Scene.nugroup" [] world - if selecting then World.defer (World.synchronizeNav3d false (Some "Assets/Gameplay/Scene.nav") screen) screen world + let sceneGroupFilePath = "Assets/Gameplay/Scene.nugroup" + let sceneNavFilePath = PathF.ChangeExtension (sceneGroupFilePath, ".nav") + World.beginGroupFromFile Simulants.GameplayScene.Name sceneGroupFilePath [] world + if selecting then World.defer (World.synchronizeNav3d false (Some sceneNavFilePath) screen) screen world // declare player World.doEntity Simulants.GameplayPlayer.Name @@ -69,11 +71,11 @@ type GameplayDispatcher () = if not (character.GetActionState world).IsInjuryState then character.SetActionState (InjuryState { InjuryTime = world.UpdateTime }) world character.LinearVelocity.Map ((*) v3Up) world // zero out horizontal velocity on injury - World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.InjureSound world + World.playSound 0.0f 0.0f 1.0f Assets.Gameplay.InjureSound world elif not (character.GetActionState world).IsWoundState then character.SetActionState (WoundState { WoundTime = world.UpdateTime }) world character.LinearVelocity.Map ((*) v3Up) world // zero out horizontal velocity on wound - World.playSound Constants.Audio.SoundVolumeDefault Assets.Gameplay.InjureSound world + World.playSound 0.0f 0.0f 1.0f Assets.Gameplay.InjureSound world // process character deaths for character in characters do diff --git a/Projects/Terra Firma/TerraFirma.fs b/Projects/Terra Firma/TerraFirma.fs index a1c6c8f7ce..73383cba06 100644 --- a/Projects/Terra Firma/TerraFirma.fs +++ b/Projects/Terra Firma/TerraFirma.fs @@ -55,7 +55,7 @@ type TerraFirmaDispatcher () = if FQueue.contains Deselecting results then Simulants.Gameplay.SetGameplayState Quit world if Simulants.Gameplay.GetSelected world && Simulants.Gameplay.GetGameplayState world = Quit && - world.Advancing then + world.Advancing then game.SetGameState Title world World.endScreen world diff --git a/Projects/Twenty 48/Assets/Default/AnimatedModelIcon.png b/Projects/Twenty 48/Assets/Default/AnimatedModelIcon.png new file mode 100644 index 0000000000..d90b86d6e0 Binary files /dev/null and b/Projects/Twenty 48/Assets/Default/AnimatedModelIcon.png differ diff --git a/Projects/Twenty 48/Assets/Default/PhysicallyBasedDeferredComposition.glsl b/Projects/Twenty 48/Assets/Default/PhysicallyBasedDeferredComposition.glsl index 955fa8d2aa..fde0945d6b 100644 --- a/Projects/Twenty 48/Assets/Default/PhysicallyBasedDeferredComposition.glsl +++ b/Projects/Twenty 48/Assets/Default/PhysicallyBasedDeferredComposition.glsl @@ -51,7 +51,7 @@ void main() vec3 fogAccum = texture(fogAccumTexture, texCoordsOut, 0).xyz; vec3 color = texture(colorTexture, texCoordsOut, 0).xyz + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled vec4 position = depthToPosition(depth, texCoordsOut); float distance = length(position.xyz - eyeCenter); if (fogEnabled == 1) diff --git a/Projects/Twenty 48/Assets/Default/PhysicallyBasedDeferredLighting.glsl b/Projects/Twenty 48/Assets/Default/PhysicallyBasedDeferredLighting.glsl index 77e145e50d..927c1b89d5 100644 --- a/Projects/Twenty 48/Assets/Default/PhysicallyBasedDeferredLighting.glsl +++ b/Projects/Twenty 48/Assets/Default/PhysicallyBasedDeferredLighting.glsl @@ -19,8 +19,8 @@ const float PI = 3.141592654; const float PI_OVER_2 = PI / 2.0; const float ATTENUATION_CONSTANT = 1.0; const int LIGHTS_MAX = 64; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -29,11 +29,11 @@ const float SHADOW_CASCADE_DENSITY_BONUS = 0.5; const float SHADOW_FOV_MAX = 2.1; const vec4 SSVF_DITHERING[4] = -vec4[]( - vec4(0.0, 0.5, 0.125, 0.625), - vec4(0.75, 0.22, 0.875, 0.375), - vec4(0.1875, 0.6875, 0.0625, 0.5625), - vec4(0.9375, 0.4375, 0.8125, 0.3125)); + vec4[]( + vec4(0.0, 0.5, 0.125, 0.625), + vec4(0.75, 0.22, 0.875, 0.375), + vec4(0.1875, 0.6875, 0.0625, 0.5625), + vec4(0.9375, 0.4375, 0.8125, 0.3125)); uniform vec3 eyeCenter; uniform mat4 view; @@ -778,11 +778,11 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; float intensity = 0.0; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); diff --git a/Projects/Twenty 48/Assets/Default/PhysicallyBasedForwardAnimated.glsl b/Projects/Twenty 48/Assets/Default/PhysicallyBasedForwardAnimated.glsl index b747954d08..3225ba701f 100644 --- a/Projects/Twenty 48/Assets/Default/PhysicallyBasedForwardAnimated.glsl +++ b/Projects/Twenty 48/Assets/Default/PhysicallyBasedForwardAnimated.glsl @@ -87,8 +87,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -862,10 +862,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1049,7 +1049,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Twenty 48/Assets/Default/PhysicallyBasedForwardStatic.glsl b/Projects/Twenty 48/Assets/Default/PhysicallyBasedForwardStatic.glsl index c326e319c4..b0f618ce49 100644 --- a/Projects/Twenty 48/Assets/Default/PhysicallyBasedForwardStatic.glsl +++ b/Projects/Twenty 48/Assets/Default/PhysicallyBasedForwardStatic.glsl @@ -68,8 +68,8 @@ const float ATTENUATION_CONSTANT = 1.0f; const float ENVIRONMENT_FILTER_REFRACTED_SATURATION = 2.0; const int LIGHT_MAPS_MAX = 2; const int LIGHTS_MAX = 9; -const int SHADOW_TEXTURES_MAX = 9; -const int SHADOW_MAPS_MAX = 9; +const int SHADOW_TEXTURES_MAX = 12; +const int SHADOW_MAPS_MAX = 12; const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size. const int SHADOW_CASCADES_MAX = 2; const int SHADOW_CASCADE_LEVELS = 3; @@ -843,10 +843,10 @@ void main() vec3 lightOrigin = lightOrigins[i]; float lightCutoff = lightCutoffs[i]; int lightType = lightTypes[i]; - bool lightDirectional = lightType == 2; - bool lightCascaded = lightType == 3; + bool lightPoint = lightType == 0; + bool lightSpot = lightType == 1; vec3 l, h, radiance; - if (!lightDirectional && !lightCascaded) + if (lightPoint || lightSpot) { vec3 d = lightOrigin - position.xyz; l = normalize(d); @@ -1030,7 +1030,7 @@ void main() // compute color composition vec3 color = lightAccumDiffuse + diffuse + emission * albedo.rgb + lightAccumSpecular + specular + fogAccum; - // compute and apply global fog when enabled + // compute and apply distance fog when enabled if (fogEnabled == 1) { switch (fogType) diff --git a/Projects/Twenty 48/Assets/Default/RawIcon.png b/Projects/Twenty 48/Assets/Default/RawIcon.png new file mode 100644 index 0000000000..34c88aad5e Binary files /dev/null and b/Projects/Twenty 48/Assets/Default/RawIcon.png differ diff --git a/Projects/Twenty 48/Assets/Default/SongIcon.png b/Projects/Twenty 48/Assets/Default/SongIcon.png new file mode 100644 index 0000000000..06599ab761 Binary files /dev/null and b/Projects/Twenty 48/Assets/Default/SongIcon.png differ diff --git a/Projects/Twenty 48/Assets/Default/SoundIcon.png b/Projects/Twenty 48/Assets/Default/SoundIcon.png new file mode 100644 index 0000000000..19913af6ad Binary files /dev/null and b/Projects/Twenty 48/Assets/Default/SoundIcon.png differ diff --git a/Projects/Twenty 48/Assets/Default/SpineSkeletonIcon.png b/Projects/Twenty 48/Assets/Default/SpineSkeletonIcon.png new file mode 100644 index 0000000000..a90b868eae Binary files /dev/null and b/Projects/Twenty 48/Assets/Default/SpineSkeletonIcon.png differ diff --git a/Projects/Twenty 48/Assets/Default/StaticModelIcon.png b/Projects/Twenty 48/Assets/Default/StaticModelIcon.png new file mode 100644 index 0000000000..eb61fc44ec Binary files /dev/null and b/Projects/Twenty 48/Assets/Default/StaticModelIcon.png differ diff --git a/Projects/Twenty 48/Assets/Default/TileMapIcon.png b/Projects/Twenty 48/Assets/Default/TileMapIcon.png new file mode 100644 index 0000000000..fe524e80d4 Binary files /dev/null and b/Projects/Twenty 48/Assets/Default/TileMapIcon.png differ diff --git a/ReadMe.md b/ReadMe.md index f9908a3574..67c1bc94d8 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -96,8 +96,6 @@ Recursive Prefab-like functionality via Entity Structure Propagation. **[@haraldsteinlechner](https://github.com/haraldsteinlechner)** -**[@ShalokShalom](https://github.com/ShalokShalom)** - **And a huge thank you to all of you who donate privately to keep this project going!** Please Become a Sponsor for Nu Today!