forked from MoonsideGames/MoonWorks
				
			Compare commits
	
		
			5 Commits 
		
	
	
		
			3ffdf8a929
			...
			4f89325d29
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | 4f89325d29 | |
|  | 66c6ceec04 | |
|  | dfddc24d0e | |
|  | b66e077376 | |
|  | 07c0b1b9a2 | 
|  | @ -1 +1 @@ | |||
| Subproject commit 356f8e9ec2a6118b75e32d2a2ed7dbf4297aba78 | ||||
| Subproject commit 330896a7be6db93b17b3b47734e449817bb30b7a | ||||
|  | @ -0,0 +1,22 @@ | |||
| namespace MoonWorks | ||||
| { | ||||
| 	public enum FrameLimiterMode | ||||
| 	{ | ||||
| 		Uncapped, | ||||
| 		Capped | ||||
| 	} | ||||
| 
 | ||||
| 	public struct FrameLimiterSettings | ||||
| 	{ | ||||
| 		public FrameLimiterMode Mode; | ||||
| 		public int Cap; | ||||
| 
 | ||||
| 		public FrameLimiterSettings( | ||||
| 			FrameLimiterMode mode, | ||||
| 			int cap | ||||
| 		) { | ||||
| 			Mode = mode; | ||||
| 			Cap = cap; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -1,14 +0,0 @@ | |||
| namespace MoonWorks | ||||
| { | ||||
| 	public enum FramerateMode | ||||
| 	{ | ||||
| 		Uncapped, | ||||
| 		Capped | ||||
| 	} | ||||
| 
 | ||||
| 	public struct FramerateSettings | ||||
| 	{ | ||||
| 		public FramerateMode Mode; | ||||
| 		public int Cap; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										58
									
								
								src/Game.cs
								
								
								
								
							
							
						
						
									
										58
									
								
								src/Game.cs
								
								
								
								
							|  | @ -29,23 +29,15 @@ namespace MoonWorks | |||
| 		private bool FramerateCapped = false; | ||||
| 		private TimeSpan FramerateCapTimeSpan = TimeSpan.Zero; | ||||
| 
 | ||||
| 		public Window Window { get; } | ||||
| 		public GraphicsDevice GraphicsDevice { get; } | ||||
| 		public AudioDevice AudioDevice { get; } | ||||
| 		public Inputs Inputs { get; } | ||||
| 
 | ||||
| 		private Dictionary<PresentMode, RefreshCS.Refresh.PresentMode> moonWorksToRefreshPresentMode = new Dictionary<PresentMode, RefreshCS.Refresh.PresentMode> | ||||
| 		{ | ||||
| 			{ PresentMode.Immediate, RefreshCS.Refresh.PresentMode.Immediate }, | ||||
| 			{ PresentMode.Mailbox, RefreshCS.Refresh.PresentMode.Mailbox }, | ||||
| 			{ PresentMode.FIFO, RefreshCS.Refresh.PresentMode.FIFO }, | ||||
| 			{ PresentMode.FIFORelaxed, RefreshCS.Refresh.PresentMode.FIFORelaxed } | ||||
| 		}; | ||||
| 		public Window MainWindow { get; } | ||||
| 
 | ||||
| 		public Game( | ||||
| 			WindowCreateInfo windowCreateInfo, | ||||
| 			PresentMode presentMode, | ||||
| 			FramerateSettings framerateSettings, | ||||
| 			FrameLimiterSettings frameLimiterSettings, | ||||
| 			int targetTimestep = 60, | ||||
| 			bool debugMode = false | ||||
| 		) | ||||
|  | @ -53,12 +45,7 @@ namespace MoonWorks | |||
| 			Timestep = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / targetTimestep); | ||||
| 			gameTimer = Stopwatch.StartNew(); | ||||
| 
 | ||||
| 			FramerateCapped = framerateSettings.Mode == FramerateMode.Capped; | ||||
| 
 | ||||
| 			if (FramerateCapped) | ||||
| 			{ | ||||
| 				FramerateCapTimeSpan = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / framerateSettings.Cap); | ||||
| 			} | ||||
| 			SetFrameLimiter(frameLimiterSettings); | ||||
| 
 | ||||
| 			for (int i = 0; i < previousSleepTimes.Length; i += 1) | ||||
| 			{ | ||||
|  | @ -75,19 +62,25 @@ namespace MoonWorks | |||
| 
 | ||||
| 			Inputs = new Inputs(); | ||||
| 
 | ||||
| 			Window = new Window(windowCreateInfo); | ||||
| 
 | ||||
| 			GraphicsDevice = new GraphicsDevice( | ||||
| 				Window.Handle, | ||||
| 				moonWorksToRefreshPresentMode[presentMode], | ||||
| 				Backend.Vulkan, | ||||
| 				debugMode | ||||
| 			); | ||||
| 
 | ||||
| 			MainWindow = new Window(windowCreateInfo, GraphicsDevice.WindowFlags | SDL.SDL_WindowFlags.SDL_WINDOW_HIDDEN); | ||||
| 
 | ||||
| 			if (!GraphicsDevice.ClaimWindow(MainWindow, windowCreateInfo.PresentMode)) | ||||
| 			{ | ||||
| 				throw new System.SystemException("Could not claim window!"); | ||||
| 			} | ||||
| 
 | ||||
| 			AudioDevice = new AudioDevice(); | ||||
| 		} | ||||
| 
 | ||||
| 		public void Run() | ||||
| 		{ | ||||
| 			MainWindow.Show(); | ||||
| 
 | ||||
| 			while (!quit) | ||||
| 			{ | ||||
| 				Tick(); | ||||
|  | @ -96,12 +89,26 @@ namespace MoonWorks | |||
| 			Destroy(); | ||||
| 
 | ||||
| 			AudioDevice.Dispose(); | ||||
| 			MainWindow.Dispose(); | ||||
| 			GraphicsDevice.Dispose(); | ||||
| 			Window.Dispose(); | ||||
| 
 | ||||
| 			SDL.SDL_Quit(); | ||||
| 		} | ||||
| 
 | ||||
| 		public void SetFrameLimiter(FrameLimiterSettings settings) | ||||
| 		{ | ||||
| 			FramerateCapped = settings.Mode == FrameLimiterMode.Capped; | ||||
| 
 | ||||
| 			if (FramerateCapped) | ||||
| 			{ | ||||
| 				FramerateCapTimeSpan = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / settings.Cap); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				FramerateCapTimeSpan = TimeSpan.Zero; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		protected abstract void Update(TimeSpan delta); | ||||
| 		protected abstract void Draw(double alpha); | ||||
| 		protected virtual void Destroy() {} | ||||
|  | @ -224,7 +231,14 @@ namespace MoonWorks | |||
| 		{ | ||||
| 			if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED) | ||||
| 			{ | ||||
| 				Window.SizeChanged((uint) evt.window.data1, (uint) evt.window.data2); | ||||
| 				var window = Window.Lookup(evt.window.windowID); | ||||
| 				window.SizeChanged((uint) evt.window.data1, (uint) evt.window.data2); | ||||
| 			} | ||||
| 			else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE) | ||||
| 			{ | ||||
| 				var window = Window.Lookup(evt.window.windowID); | ||||
| 				GraphicsDevice.UnclaimWindow(window); | ||||
| 				window.Dispose(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,15 +13,18 @@ namespace MoonWorks.Graphics | |||
| 		public IntPtr Handle { get; } | ||||
| 
 | ||||
| 		// some state for debug validation | ||||
| 		GraphicsPipeline currentGraphicsPipeline = null; | ||||
| 		ComputePipeline currentComputePipeline = null; | ||||
| 		bool renderPassActive = false; | ||||
| 		GraphicsPipeline currentGraphicsPipeline; | ||||
| 		ComputePipeline currentComputePipeline; | ||||
| 		bool renderPassActive; | ||||
| 
 | ||||
| 		// called from RefreshDevice | ||||
| 		internal CommandBuffer(GraphicsDevice device, IntPtr handle) | ||||
| 		{ | ||||
| 			Device = device; | ||||
| 			Handle = handle; | ||||
| 			currentGraphicsPipeline = null; | ||||
| 			currentComputePipeline = null; | ||||
| 			renderPassActive = false; | ||||
| 		} | ||||
| 
 | ||||
| 		// FIXME: we can probably use the NativeMemory functions to not have to generate arrays here | ||||
|  | @ -815,7 +818,7 @@ namespace MoonWorks.Graphics | |||
| 			return new Texture( | ||||
| 				Device, | ||||
| 				texturePtr, | ||||
| 				Device.GetSwapchainFormat(window), | ||||
| 				window.SwapchainFormat, | ||||
| 				width, | ||||
| 				height | ||||
| 			); | ||||
|  |  | |||
|  | @ -8,6 +8,10 @@ namespace MoonWorks.Graphics | |||
| 	public class GraphicsDevice : IDisposable | ||||
| 	{ | ||||
| 		public IntPtr Handle { get; } | ||||
| 		public Backend Backend { get; } | ||||
| 
 | ||||
| 		private uint windowFlags; | ||||
| 		public SDL2.SDL.SDL_WindowFlags WindowFlags => (SDL2.SDL.SDL_WindowFlags) windowFlags; | ||||
| 
 | ||||
| 		// Built-in video pipeline | ||||
| 		private ShaderModule VideoVertexShader { get; } | ||||
|  | @ -18,25 +22,44 @@ namespace MoonWorks.Graphics | |||
| 
 | ||||
| 		private readonly List<WeakReference<GraphicsResource>> resources = new List<WeakReference<GraphicsResource>>(); | ||||
| 
 | ||||
| 		private static bool usingCustomVideoShaders; | ||||
| 		private static string customVideoVertexShaderFilepath; | ||||
| 		private static string customVideoFragmentShaderFilepath; | ||||
| 
 | ||||
| 		public GraphicsDevice( | ||||
| 			IntPtr deviceWindowHandle, | ||||
| 			Refresh.PresentMode presentMode, | ||||
| 			Backend preferredBackend, | ||||
| 			bool debugMode | ||||
| 		) | ||||
| 		{ | ||||
| 			var presentationParameters = new Refresh.PresentationParameters | ||||
| 			Backend = (Backend) Refresh.Refresh_SelectBackend((Refresh.Backend) preferredBackend, out windowFlags); | ||||
| 
 | ||||
| 			if (Backend == Backend.Invalid) | ||||
| 			{ | ||||
| 				deviceWindowHandle = deviceWindowHandle, | ||||
| 				presentMode = presentMode | ||||
| 			}; | ||||
| 				throw new System.Exception("Could not set graphics backend!"); | ||||
| 			} | ||||
| 
 | ||||
| 			Handle = Refresh.Refresh_CreateDevice( | ||||
| 				presentationParameters, | ||||
| 				Conversions.BoolToByte(debugMode) | ||||
| 			); | ||||
| 
 | ||||
| 			VideoVertexShader = new ShaderModule(this, GetEmbeddedResource("MoonWorks.Shaders.FullscreenVert.spv")); | ||||
| 			VideoFragmentShader = new ShaderModule(this, GetEmbeddedResource("MoonWorks.Shaders.YUV2RGBAFrag.spv")); | ||||
| 			Stream videoVertexShaderStream; | ||||
| 			Stream videoFragmentShaderStream; | ||||
| 			if (!usingCustomVideoShaders) | ||||
| 			{ | ||||
| 				videoVertexShaderStream = GetEmbeddedResource("MoonWorks.Shaders.FullscreenVert.spv"); | ||||
| 				videoFragmentShaderStream = GetEmbeddedResource("MoonWorks.Shaders.YUV2RGBAFrag.spv"); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				videoVertexShaderStream = File.Open(customVideoVertexShaderFilepath, FileMode.Open, FileAccess.Read); | ||||
| 				videoFragmentShaderStream = File.Open(customVideoFragmentShaderFilepath, FileMode.Open, FileAccess.Read); | ||||
| 			} | ||||
| 
 | ||||
| 			VideoVertexShader = new ShaderModule(this, videoVertexShaderStream); | ||||
| 			VideoFragmentShader = new ShaderModule(this, videoFragmentShaderStream); | ||||
| 
 | ||||
| 			videoVertexShaderStream.Close(); | ||||
| 			videoFragmentShaderStream.Close(); | ||||
| 
 | ||||
| 			VideoPipeline = new GraphicsPipeline( | ||||
| 				this, | ||||
|  | @ -56,6 +79,43 @@ namespace MoonWorks.Graphics | |||
| 			); | ||||
| 		} | ||||
| 
 | ||||
| 		public bool ClaimWindow(Window window, PresentMode presentMode) | ||||
| 		{ | ||||
| 			var success = Conversions.ByteToBool( | ||||
| 				Refresh.Refresh_ClaimWindow( | ||||
| 					Handle, | ||||
| 					window.Handle, | ||||
| 					(Refresh.PresentMode) presentMode | ||||
| 				) | ||||
| 			); | ||||
| 
 | ||||
| 			if (success) | ||||
| 			{ | ||||
| 				window.Claimed = true; | ||||
| 				window.SwapchainFormat = GetSwapchainFormat(window); | ||||
| 			} | ||||
| 
 | ||||
| 			return success; | ||||
| 		} | ||||
| 
 | ||||
| 		public void UnclaimWindow(Window window) | ||||
| 		{ | ||||
| 			Refresh.Refresh_UnclaimWindow( | ||||
| 				Handle, | ||||
| 				window.Handle | ||||
| 			); | ||||
| 			window.Claimed = false; | ||||
| 		} | ||||
| 
 | ||||
| 		public void SetPresentMode(Window window, PresentMode presentMode) | ||||
| 		{ | ||||
| 			Refresh.Refresh_SetSwapchainPresentMode( | ||||
| 				Handle, | ||||
| 				window.Handle, | ||||
| 				(Refresh.PresentMode) presentMode | ||||
| 			); | ||||
| 		} | ||||
| 
 | ||||
| 		public CommandBuffer AcquireCommandBuffer() | ||||
| 		{ | ||||
| 			return new CommandBuffer(this, Refresh.Refresh_AcquireCommandBuffer(Handle, 0)); | ||||
|  | @ -82,7 +142,7 @@ namespace MoonWorks.Graphics | |||
| 			Refresh.Refresh_Wait(Handle); | ||||
| 		} | ||||
| 
 | ||||
| 		public TextureFormat GetSwapchainFormat(Window window) | ||||
| 		private TextureFormat GetSwapchainFormat(Window window) | ||||
| 		{ | ||||
| 			return (TextureFormat) Refresh.Refresh_GetSwapchainFormat(Handle, window.Handle); | ||||
| 		} | ||||
|  | @ -108,6 +168,16 @@ namespace MoonWorks.Graphics | |||
| 			return typeof(GraphicsDevice).Assembly.GetManifestResourceStream(name); | ||||
| 		} | ||||
| 
 | ||||
| 		/// <summary> | ||||
| 		/// Use this ONLY for platforms with non-standard graphics APIs where the shader code can't be embedded into the assembly! | ||||
| 		/// </summary> | ||||
| 		public static void UseCustomVideoShaders(string vertexShaderFilePath, string fragmentShaderFilePath) | ||||
| 		{ | ||||
| 			usingCustomVideoShaders = true; | ||||
| 			customVideoVertexShaderFilepath = vertexShaderFilePath; | ||||
| 			customVideoFragmentShaderFilepath = fragmentShaderFilePath; | ||||
| 		} | ||||
| 
 | ||||
| 		protected virtual void Dispose(bool disposing) | ||||
| 		{ | ||||
| 			if (!IsDisposed) | ||||
|  |  | |||
|  | @ -1,9 +1,6 @@ | |||
| using System; | ||||
| 
 | ||||
| /* Recreate all the enums in here so we don't need to explicitly | ||||
|  * reference the RefreshCS namespace when using MoonWorks.Graphics | ||||
|  */ | ||||
| namespace MoonWorks.Graphics | ||||
| namespace MoonWorks | ||||
| { | ||||
| 	public enum PresentMode | ||||
| 	{ | ||||
|  | @ -12,7 +9,13 @@ namespace MoonWorks.Graphics | |||
| 		FIFO, | ||||
| 		FIFORelaxed | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Recreate all the enums in here so we don't need to explicitly | ||||
|  * reference the RefreshCS namespace when using MoonWorks.Graphics | ||||
|  */ | ||||
| namespace MoonWorks.Graphics | ||||
| { | ||||
| 	public enum PrimitiveType | ||||
| 	{ | ||||
| 		PointList, | ||||
|  | @ -280,4 +283,12 @@ namespace MoonWorks.Graphics | |||
| 		FloatOpaqueWhite, | ||||
| 		IntOpaqueWhite | ||||
| 	} | ||||
| 
 | ||||
| 	public enum Backend | ||||
| 	{ | ||||
| 		DontCare, | ||||
| 		Vulkan, | ||||
| 		PS5, | ||||
| 		Invalid | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using SDL2; | ||||
| 
 | ||||
| namespace MoonWorks | ||||
|  | @ -10,29 +11,32 @@ namespace MoonWorks | |||
| 		public uint Width { get; private set; } | ||||
| 		public uint Height { get; private set; } | ||||
| 
 | ||||
| 		public bool Claimed { get; internal set; } | ||||
| 		public MoonWorks.Graphics.TextureFormat SwapchainFormat { get; internal set; } | ||||
| 
 | ||||
| 		private bool IsDisposed; | ||||
| 
 | ||||
| 		public Window(WindowCreateInfo windowCreateInfo) | ||||
| 		{ | ||||
| 			var windowFlags = SDL.SDL_WindowFlags.SDL_WINDOW_VULKAN; | ||||
| 		private static Dictionary<uint, Window> idLookup = new Dictionary<uint, Window>(); | ||||
| 
 | ||||
| 		public Window(WindowCreateInfo windowCreateInfo, SDL.SDL_WindowFlags flags) | ||||
| 		{ | ||||
| 			if (windowCreateInfo.ScreenMode == ScreenMode.Fullscreen) | ||||
| 			{ | ||||
| 				windowFlags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN; | ||||
| 				flags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN; | ||||
| 			} | ||||
| 			else if (windowCreateInfo.ScreenMode == ScreenMode.BorderlessWindow) | ||||
| 			{ | ||||
| 				windowFlags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP; | ||||
| 				flags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP; | ||||
| 			} | ||||
| 
 | ||||
| 			if (windowCreateInfo.SystemResizable) | ||||
| 			{ | ||||
| 				windowFlags |= SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE; | ||||
| 				flags |= SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE; | ||||
| 			} | ||||
| 
 | ||||
| 			if (windowCreateInfo.StartMaximized) | ||||
| 			{ | ||||
| 				windowFlags |= SDL.SDL_WindowFlags.SDL_WINDOW_MAXIMIZED; | ||||
| 				flags |= SDL.SDL_WindowFlags.SDL_WINDOW_MAXIMIZED; | ||||
| 			} | ||||
| 
 | ||||
| 			ScreenMode = windowCreateInfo.ScreenMode; | ||||
|  | @ -43,11 +47,13 @@ namespace MoonWorks | |||
| 				SDL.SDL_WINDOWPOS_UNDEFINED, | ||||
| 				(int) windowCreateInfo.WindowWidth, | ||||
| 				(int) windowCreateInfo.WindowHeight, | ||||
| 				windowFlags | ||||
| 				flags | ||||
| 			); | ||||
| 
 | ||||
| 			Width = windowCreateInfo.WindowWidth; | ||||
| 			Height = windowCreateInfo.WindowHeight; | ||||
| 
 | ||||
| 			idLookup.Add(SDL.SDL_GetWindowID(Handle), this); | ||||
| 		} | ||||
| 
 | ||||
| 		public void ChangeScreenMode(ScreenMode screenMode) | ||||
|  | @ -81,6 +87,16 @@ namespace MoonWorks | |||
| 			Height = height; | ||||
| 		} | ||||
| 
 | ||||
| 		internal static Window Lookup(uint windowID) | ||||
| 		{ | ||||
| 			return idLookup.ContainsKey(windowID) ? idLookup[windowID] : null; | ||||
| 		} | ||||
| 
 | ||||
| 		internal void Show() | ||||
| 		{ | ||||
| 			SDL.SDL_ShowWindow(Handle); | ||||
| 		} | ||||
| 
 | ||||
| 		internal void SizeChanged(uint width, uint height) | ||||
| 		{ | ||||
| 			Width = width; | ||||
|  | @ -96,6 +112,7 @@ namespace MoonWorks | |||
| 					// dispose managed state (managed objects) | ||||
| 				} | ||||
| 
 | ||||
| 				idLookup.Remove(SDL.SDL_GetWindowID(Handle)); | ||||
| 				SDL.SDL_DestroyWindow(Handle); | ||||
| 
 | ||||
| 				IsDisposed = true; | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| 		public uint WindowWidth; | ||||
| 		public uint WindowHeight; | ||||
| 		public ScreenMode ScreenMode; | ||||
| 		public PresentMode PresentMode; | ||||
| 		public bool SystemResizable; | ||||
| 		public bool StartMaximized; | ||||
| 
 | ||||
|  | @ -14,6 +15,7 @@ | |||
| 			uint windowWidth, | ||||
| 			uint windowHeight, | ||||
| 			ScreenMode screenMode, | ||||
| 			PresentMode presentMode, | ||||
| 			bool systemResizable = false, | ||||
| 			bool startMaximized = false | ||||
| 		) { | ||||
|  | @ -21,6 +23,7 @@ | |||
| 			WindowWidth = windowWidth; | ||||
| 			WindowHeight = windowHeight; | ||||
| 			ScreenMode = screenMode; | ||||
| 			PresentMode = presentMode; | ||||
| 			SystemResizable = systemResizable; | ||||
| 			StartMaximized = startMaximized; | ||||
| 		} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue