/// <summary> /// Attempts to create a new instance of the specified Ultraviolet subsystem by dynamically loading it from the specified assembly. /// </summary> /// <typeparam name="TSubsystem">The subsystem interface type.</typeparam> /// <param name="assembly">The assembly from which to load the subsystem implementation.</param> /// <param name="configuration">The Ultraviolet context configuration.</param> /// <param name="instance">The subsystem instance that was created.</param> /// <returns><see langword="true"/> if the subsystem instance was created; otherwise, <see langword="false"/>.</returns> private Boolean TryCreateSubsystemInstance <TSubsystem>(Assembly assembly, UltravioletConfiguration configuration, out TSubsystem instance) { var types = (from t in assembly.GetTypes() where t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(typeof(TSubsystem)) select t).ToList(); if (!types.Any() || types.Count > 1) { throw new InvalidOperationException(SDL2Strings.InvalidAudioAssembly); } var type = types.Single(); var ctorWithConfig = type.GetConstructor(new[] { typeof(UltravioletContext), typeof(UltravioletConfiguration) }); if (ctorWithConfig != null) { instance = (TSubsystem)ctorWithConfig.Invoke(new object[] { this, configuration }); return(true); } var ctorWithoutConfig = type.GetConstructor(new[] { typeof(UltravioletContext) }); if (ctorWithoutConfig != null) { instance = (TSubsystem)ctorWithoutConfig.Invoke(new object[] { this }); return(true); } instance = default(TSubsystem); return(false); }
/// <summary> /// Initializes debug output for this context. /// </summary> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> private void InitializeDebugOutput(UltravioletConfiguration configuration) { if (!gl.IsExtensionSupported("GL_ARB_debug_output")) { Debug.WriteLine(OpenGLStrings.DebugOutputNotSupported); return; } debugCallback = configuration.DebugCallback; debugCallbackOpenGL = DebugCallbackThunk; gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.GL_DONT_CARE, 0, IntPtr.Zero, false); if ((configuration.DebugLevels & DebugLevels.Info) == DebugLevels.Info) { gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_LOW, 0, IntPtr.Zero, true); gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_NOTIFICATION, 0, IntPtr.Zero, true); } if ((configuration.DebugLevels & DebugLevels.Warning) == DebugLevels.Warning) { gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_MEDIUM, 0, IntPtr.Zero, true); } if ((configuration.DebugLevels & DebugLevels.Error) == DebugLevels.Error) { gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_HIGH, 0, IntPtr.Zero, true); } gl.DebugMessageCallback(debugCallbackOpenGL, IntPtr.Zero); }
/// <summary> /// Initializes a new instance of the <see cref="SDL2UltravioletContext"/> class. /// </summary> /// <param name="host">The object that is hosting the Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework configuration settings for this context.</param> protected unsafe SDL2UltravioletContext(IUltravioletHost host, UltravioletConfiguration configuration) : base(host, configuration) { eventFilter = new SDL_EventFilter(SDLEventFilter); eventFilterPtr = Marshal.GetFunctionPointerForDelegate(eventFilter); SDL_SetEventFilter(eventFilterPtr, IntPtr.Zero); }
/// <summary> /// Initializes a new instance of the <see cref="SDL2UltravioletWindowInfo"/> class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet configuration settings for the current context.</param> internal SDL2UltravioletWindowInfo(UltravioletContext uv, UltravioletConfiguration configuration) { Contract.Require(uv, nameof(uv)); Contract.Require(configuration, nameof(configuration)); this.Ultraviolet = uv; }
/// <inheritdoc/> public override void Configure(UltravioletConfiguration ultravioletConfig) { Contract.Require(ultravioletConfig, nameof(ultravioletConfig)); ultravioletConfig.ViewProviderAssembly = typeof(ImGuiPlugin).Assembly.FullName; ultravioletConfig.ViewProviderConfiguration = null; }
/// <summary> /// Initializes a new instance of the <see cref="SDL2UltravioletPlatform"/> class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="uvconfig">The Ultraviolet Framework's configuration settings.</param> /// <param name="sdlconfig">The SDL2 platform configuration settings.</param> public SDL2UltravioletPlatform(UltravioletContext uv, UltravioletConfiguration uvconfig, SDL2PlatformConfiguration sdlconfig) : base(uv) { this.clipboard = ClipboardService.Create(); this.messageBoxService = MessageBoxService.Create(); this.windows = new SDL2UltravioletWindowInfoOpenGL(uv, uvconfig, sdlconfig); this.displays = new SDL2UltravioletDisplayInfo(uv); }
/// <summary> /// Initializes a new instance of the <see cref="SDL2UltravioletPlatform"/> class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework's configuration settings.</param> public SDL2UltravioletPlatform(UltravioletContext uv, UltravioletConfiguration configuration) : base(uv) { this.clipboard = ClipboardService.Create(); this.messageBoxService = MessageBoxService.Create(); this.windows = new SDL2UltravioletWindowInfoOpenGL(uv, configuration); this.displays = new SDL2UltravioletDisplayInfo(uv); this.isCursorVisible = SDL_ShowCursor(SDL_QUERY) != 0; }
/// <summary> /// Initializes a new instance of the <see cref="SDL2UltravioletWindowInfo"/> class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="uvconfig">The Ultraviolet configuration settings for the current context.</param> /// <param name="winconfig">The window configuration settings for the current context.</param> internal SDL2UltravioletWindowInfo(UltravioletContext uv, UltravioletConfiguration uvconfig, SDL2PlatformConfiguration winconfig) { Contract.Require(uv, nameof(uv)); Contract.Require(uvconfig, nameof(uvconfig)); Contract.Require(winconfig, nameof(winconfig)); this.uv = uv; InitializePrimaryWindow(uvconfig, winconfig); }
/// <summary> /// Initializes a new instance of the <see cref="UltravioletUI"/> class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> public UltravioletUI(UltravioletContext uv, UltravioletConfiguration configuration) : base(uv) { screenStacks = new UIScreenStackCollection(uv); if (uv.Platform != UltravioletPlatform.Android && uv.Platform != UltravioletPlatform.iOS) { WatchingViewFilesForChanges = configuration.WatchViewFilesForChanges; } }
/// <summary> /// Initializes a new instance of the <see cref="UltravioletUI"/> class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> public UltravioletUI(UltravioletContext uv, UltravioletConfiguration configuration) : base(uv) { screenStacks = new UIScreenStackCollection(uv); if (ContentManager.IsWatchedContentSupported) { WatchingViewFilesForChanges = configuration.WatchViewFilesForChanges; } }
/// <inheritdoc/> public override void Register(UltravioletConfiguration configuration) { Contract.Require(configuration, nameof(configuration)); var asm = typeof(BASSAudioPlugin).Assembly; configuration.AudioSubsystemAssembly = $"{asm.GetName().Name}, Version={asm.GetName().Version}, Culture=neutral, PublicKeyToken=78da2f4877323311, processorArchitecture=MSIL"; base.Register(configuration); }
/// <summary> /// Loads the context's subsystem assemblies. /// </summary> /// <param name="configuration">The context's configuration settings.</param> private void LoadSubsystemAssemblies(UltravioletConfiguration configuration) { if (IsRunningInServiceMode) { return; } Assembly LoadSubsystemAssembly(String name) { try { return(Assembly.Load(name)); } catch (Exception e) { if (e is FileNotFoundException || e is FileLoadException || e is BadImageFormatException) { return(null); } throw; } } if (String.IsNullOrEmpty(configuration.GraphicsSubsystemAssembly)) { throw new InvalidOperationException(SDL2Strings.MissingGraphicsAssembly); } if (String.IsNullOrEmpty(configuration.AudioSubsystemAssembly)) { throw new InvalidOperationException(SDL2Strings.MissingAudioAssembly); } this.GraphicsSubsystemAssembly = LoadSubsystemAssembly(configuration.GraphicsSubsystemAssembly); if (this.GraphicsSubsystemAssembly == null) { throw new InvalidOperationException(SDL2Strings.InvalidGraphicsAssembly); } this.AudioSubsystemAssembly = LoadSubsystemAssembly(configuration.AudioSubsystemAssembly); if (this.AudioSubsystemAssembly == null) { throw new InvalidOperationException(SDL2Strings.InvalidAudioAssembly); } var distinctAssemblies = new[] { this.GraphicsSubsystemAssembly, this.AudioSubsystemAssembly }.Distinct(); foreach (var distinctAssembly in distinctAssemblies) { InitializeFactoryMethodsInAssembly(distinctAssembly); } }
/// <summary> /// Initializes the context's platform subsystem. /// </summary> /// <param name="configuration">The Ultraviolet Framework configuration settings for this context.</param> /// <returns>The platform subsystem.</returns> private IUltravioletPlatform InitializePlatformSubsystem(UltravioletConfiguration configuration) { if (IsRunningInServiceMode) { return(new DummyUltravioletPlatform(this)); } else { var platform = new SDL2UltravioletPlatform(this, configuration); PumpEvents(); return(platform); } }
/// <summary> /// Initializes SDL2. /// </summary> /// <param name="configuration">The Ultraviolet Framework configuration settings for this context.</param> /// <returns><see langword="true"/> if SDL2 was successfully initialized; otherwise, <see langword="false"/>.</returns> protected Boolean InitSDL(UltravioletConfiguration configuration) { var sdlFlags = configuration.EnableServiceMode ? SDL_INIT_TIMER | SDL_INIT_EVENTS : SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS; if (Platform == UltravioletPlatform.Windows) { SDL_SetHint(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, "1"); } return(SDL_Init(sdlFlags) == 0); }
/// <summary> /// Initializes the context's graphics subsystem. /// </summary> /// <param name="configuration">The Ultraviolet Framework configuration settings for this context.</param> /// <returns>The graphics subsystem.</returns> private IUltravioletGraphics InitializeGraphicsSubsystem(UltravioletConfiguration configuration) { if (IsRunningInServiceMode) { return(new DummyUltravioletGraphics(this)); } if (!TryCreateSubsystemInstance <IUltravioletGraphics>(GraphicsSubsystemAssembly, configuration, out var graphics)) { throw new InvalidOperationException(SDL2Strings.InvalidGraphicsAssembly); } return(graphics); }
/// <summary> /// Initializes the context's audio subsystem. /// </summary> /// <param name="configuration">The Ultraviolet Framework configuration settings for this context.</param> /// <returns>The audio subsystem.</returns> private IUltravioletAudio InitializeAudioSubsystem(UltravioletConfiguration configuration) { if (IsRunningInServiceMode) { return(new DummyUltravioletAudio(this)); } if (!TryCreateSubsystemInstance <IUltravioletAudio>(AudioSubsystemAssembly, configuration, out var audio)) { throw new InvalidOperationException(SDL2Strings.InvalidAudioAssembly); } return(audio); }
/// <inheritdoc/> public void InitializePrimaryWindow(UltravioletConfiguration configuration) { if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } if (IsPrimaryWindowInitialized) { throw new InvalidOperationException(); } this.windows.InitializePrimaryWindow(Ultraviolet, configuration); this.IsPrimaryWindowInitialized = true; }
/// <summary> /// Initializes debug output for this context. /// </summary> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> private void InitializeDebugOutput(UltravioletConfiguration configuration) { if (!gl.IsExtensionSupported("GL_ARB_debug_output")) { Debug.WriteLine(OpenGLStrings.DebugOutputNotSupported); return; } debugCallback = configuration.DebugCallback; debugCallbackOpenGL = (source, type, id, severity, length, message, userParam) => { var messageString = Marshal.PtrToStringAnsi(message, length); var messageLevel = DebugLevels.Info; switch (severity) { case gl.DEBUG_SEVERITY_MEDIUM: messageLevel = DebugLevels.Warning; break; case gl.DEBUG_SEVERITY_HIGH: messageLevel = DebugLevels.Error; break; } debugCallback(Ultraviolet, messageLevel, messageString); }; gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.GL_DONT_CARE, 0, IntPtr.Zero, false); if ((configuration.DebugLevels & DebugLevels.Info) == DebugLevels.Info) { gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_LOW, 0, IntPtr.Zero, true); gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_NOTIFICATION, 0, IntPtr.Zero, true); } if ((configuration.DebugLevels & DebugLevels.Warning) == DebugLevels.Warning) { gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_MEDIUM, 0, IntPtr.Zero, true); } if ((configuration.DebugLevels & DebugLevels.Error) == DebugLevels.Error) { gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_HIGH, 0, IntPtr.Zero, true); } gl.DebugMessageCallback(debugCallbackOpenGL, IntPtr.Zero); }
/// <summary> /// Initializes a new instance of the OpenGLUltravioletGraphics class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> public OpenGLUltravioletGraphics(OpenGLUltravioletContext uv, UltravioletConfiguration configuration) : base(uv) { if (configuration.Debug) { SDL.GL_SetAttribute(SDL_GLattr.CONTEXT_FLAGS, (int)SDL_GLcontextFlag.DEBUG); } var masterptr = ((OpenGLUltravioletWindowInfo)uv.GetPlatform().Windows).GetMasterPointer(); if ((this.context = SDL.GL_CreateContext(masterptr)) == IntPtr.Zero) throw new SDL2Exception(); if (SDL.GL_SetSwapInterval(0) < 0) throw new SDL2Exception(); if (gl.Initialized) { gl.Uninitialize(); } gl.Initialize(new OpenGLInitializer()); OpenGLState.ResetCache(); if (!VerifyCapabilities()) throw new NotSupportedException(OpenGLStrings.UnsupportedGraphicsDevice); if (configuration.Debug && configuration.DebugCallback != null) { InitializeDebugOutput(configuration); } this.maxTextureStages = Math.Min(16, gl.GetInteger(gl.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)); this.textures = new Texture2D[maxTextureStages]; this.samplerStates = new SamplerState[maxTextureStages]; this.capabilities = new OpenGLGraphicsCapabilities(); ResetDeviceStates(); }
/// <summary> /// Initializes a new instance of the OpenGLUltravioletGraphics class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> public OpenGLUltravioletGraphics(OpenGLUltravioletContext uv, UltravioletConfiguration configuration) : base(uv) { if (configuration.Debug) { SDL.GL_SetAttribute(SDL_GLattr.CONTEXT_FLAGS, (int)SDL_GLcontextFlag.DEBUG); } var masterptr = ((OpenGLUltravioletWindowInfo)uv.GetPlatform().Windows).GetMasterPointer(); if ((this.context = SDL.GL_CreateContext(masterptr)) == IntPtr.Zero) { if (configuration.Debug) { SDL.GL_SetAttribute(SDL_GLattr.CONTEXT_FLAGS, 0); if ((this.context = SDL.GL_CreateContext(masterptr)) == IntPtr.Zero) { throw new SDL2Exception(); } } else { throw new SDL2Exception(); } } if (SDL.GL_SetSwapInterval(1) < 0) { throw new SDL2Exception(); } if (gl.Initialized) { gl.Uninitialize(); } gl.Initialize(new OpenGLInitializer()); OpenGLState.ResetCache(); if (!VerifyCapabilities()) { throw new NotSupportedException(OpenGLStrings.UnsupportedGraphicsDevice); } if (configuration.Debug && configuration.DebugCallback != null) { InitializeDebugOutput(configuration); } this.capabilities = new OpenGLGraphicsCapabilities(); this.maxTextureStages = gl.GetInteger(gl.GL_MAX_TEXTURE_IMAGE_UNITS); this.textures = new Texture2D[maxTextureStages]; this.samplerStates = new SamplerState[maxTextureStages]; this.samplerObjects = capabilities.SupportsIndependentSamplerState ? new OpenGLSamplerObject[maxTextureStages] : null; this.backBufferRenderTargetUsage = configuration.BackBufferRenderTargetUsage; if (samplerObjects != null) { for (int i = 0; i < samplerObjects.Length; i++) { samplerObjects[i] = new OpenGLSamplerObject(Ultraviolet); samplerObjects[i].Bind((uint)i); } } OpenGLState.VerifyCache(); ResetDeviceStates(); }
/// <summary> /// Initializes a new instance of the <see cref="SDL2UltravioletWindowInfoOpenGL"/> class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet configuration settings for the current context.</param> public SDL2UltravioletWindowInfoOpenGL(UltravioletContext uv, UltravioletConfiguration configuration) : base(uv, configuration) { }
/// <summary> /// Initializes the context's primary window. /// </summary> internal void InitializePrimaryWindow(UltravioletContext uv, UltravioletConfiguration configuration) { if (Master != null) { throw new InvalidOperationException(UltravioletStrings.PrimaryWindowAlreadyInitialized); } // Initialize the rendering API. InitializeRenderingAPI(configuration.GraphicsConfiguration, 0); // If we're running on Android or iOS, we can't create a headless context. var isRunningOnMobile = (Ultraviolet.Platform == UltravioletPlatform.Android || Ultraviolet.Platform == UltravioletPlatform.iOS); if (isRunningOnMobile && configuration.Headless) { throw new InvalidOperationException(SDL2Strings.CannotCreateHeadlessContextOnMobile); } // Initialize the hidden master window used to create the OpenGL context. var masterWidth = 0; var masterHeight = 0; var masterFlags = (RenderingApi == SDL2PlatformRenderingAPI.OpenGL) ? SDL_WINDOW_OPENGL : 0; if (Ultraviolet.Properties.SupportsHighDensityDisplayModes) { masterFlags |= SDL_WINDOW_ALLOW_HIGHDPI; } if (isRunningOnMobile) { masterFlags |= SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE; } else { masterFlags |= SDL_WINDOW_HIDDEN; } // Attempt to create the master window. If that fails, reduce our requirements and try again before failing. var caption = String.IsNullOrEmpty(uv.Host.ApplicationName) ? (String)UltravioletStrings.DefaultWindowCaption : uv.Host.ApplicationName; var masterptr = SDL_CreateWindow(isRunningOnMobile ? caption : String.Empty, 0, 0, masterWidth, masterHeight, masterFlags); if (masterptr == IntPtr.Zero) { var fallbackAttempt = 1; while (InitializeRenderingAPI(configuration.GraphicsConfiguration, fallbackAttempt++)) { masterptr = SDL_CreateWindow(isRunningOnMobile ? caption : String.Empty, 0, 0, masterWidth, masterHeight, masterFlags); if (masterptr != IntPtr.Zero) { break; } } if (masterptr == IntPtr.Zero) { throw new SDL2Exception(); } // Fallback might have disabled sRGB, so update our configuration to reflect our current state. var srgbFramebufferEnabled = 0; unsafe { if (SDL_GL_GetAttribute(SDL_GLattr.SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, &srgbFramebufferEnabled) < 0) { throw new SDL2Exception(); } } configuration.GraphicsConfiguration.SrgbBuffersEnabled = (srgbFramebufferEnabled > 0); } this.Master = new SDL2UltravioletWindow(Ultraviolet, masterptr, isRunningOnMobile); // Set SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT so that enlisted windows // will be OpenGL-enabled and set to the correct pixel format. if (!SDL_SetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, masterptr.ToStringHex())) { throw new SDL2Exception(); } // If this is not a headless context, create the primary application window. if (!configuration.Headless) { if (isRunningOnMobile) { this.windows.Add(this.Master); DesignatePrimary(this.Master); } else { var flags = configuration.WindowIsVisible ? WindowFlags.None : WindowFlags.Hidden; if (configuration.WindowIsResizable) { flags |= WindowFlags.Resizable; } if (configuration.WindowIsBorderless) { flags |= WindowFlags.Borderless; } if (configuration.WindowIsShownImmediately) { flags |= WindowFlags.ShownImmediately; } var primary = Create(caption, configuration.InitialWindowPosition.X, configuration.InitialWindowPosition.Y, configuration.InitialWindowPosition.Width, configuration.InitialWindowPosition.Height, flags); DesignatePrimary(primary); } } }
/// <summary> /// Initializes debug output for this context. /// </summary> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> private void InitializeDebugOutput(UltravioletConfiguration configuration) { if (!gl.IsExtensionSupported("GL_ARB_debug_output")) { Debug.WriteLine(OpenGLStrings.DebugOutputNotSupported); return; } debugCallback = configuration.DebugCallback; debugCallbackOpenGL = DebugCallbackThunk; gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.GL_DONT_CARE, 0, IntPtr.Zero, false); if ((configuration.DebugLevels & DebugLevels.Info) == DebugLevels.Info) { gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_LOW, 0, IntPtr.Zero, true); gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_NOTIFICATION, 0, IntPtr.Zero, true); } if ((configuration.DebugLevels & DebugLevels.Warning) == DebugLevels.Warning) gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_MEDIUM, 0, IntPtr.Zero, true); if ((configuration.DebugLevels & DebugLevels.Error) == DebugLevels.Error) gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_HIGH, 0, IntPtr.Zero, true); gl.DebugMessageCallback(debugCallbackOpenGL, IntPtr.Zero); }
/// <summary> /// Initializes a new instance of the <see cref="OpenGLGraphicsCapabilities"/> class. /// </summary> /// <param name="configuration">The configuration settings for the Ultraviolet context.</param> internal unsafe OpenGLGraphicsCapabilities(UltravioletConfiguration configuration) { var glGraphicsConfiguration = configuration.GraphicsConfiguration as OpenGLGraphicsConfiguration; if (glGraphicsConfiguration == null) { throw new InvalidOperationException(OpenGLStrings.InvalidGraphicsConfiguration); } this.MaximumTextureSize = gl.GetInteger(gl.GL_MAX_TEXTURE_SIZE); gl.ThrowIfError(); var viewportDims = stackalloc int[2]; gl.GetIntegerv(gl.GL_MAX_VIEWPORT_DIMS, viewportDims); gl.ThrowIfError(); this.MaximumViewportWidth = viewportDims[0]; this.MaximumViewportHeight = viewportDims[1]; this.SupportsInstancedRendering = gl.IsInstancedRenderingAvailable; this.Supports3DTextures = gl.IsTexture3DAvailable; this.SupportsDepthStencilTextures = gl.IsCombinedDepthStencilAvailable; if (gl.IsGLES2 && !this.SupportsDepthStencilTextures) { // HACK: Guess what? The Visual Studio Emulator for Android flat-out lies about this. // So it seems the only reliable way to determine support for depth/stencil is to // actually try to create one and see if it fails. I hate Android emulators. var rb = gl.GenRenderbuffer(); using (var state = OpenGLState.ScopedBindRenderbuffer(rb, true)) { gl.RenderbufferStorage(gl.GL_RENDERBUFFER, gl.GL_DEPTH24_STENCIL8, 32, 32); this.SupportsDepthStencilTextures = (gl.GetError() == gl.GL_NO_ERROR); } gl.DeleteRenderBuffers(rb); } this.SupportsNonZeroBaseInstance = gl.IsNonZeroBaseInstanceAvailable; this.SupportsIndependentSamplerState = gl.IsSamplerObjectAvailable; this.SupportsIntegerVertexAttributes = gl.IsIntegerVertexAttribAvailable; this.SupportsDoublePrecisionVertexAttributes = gl.IsDoublePrecisionVertexAttribAvailable; this.MinMapBufferAlignment = gl.IsExtensionSupported("GL_ARB_map_buffer_alignment") ? gl.GetInteger(gl.GL_MIN_MAP_BUFFER_ALIGNMENT) : 0; // SRGB is always supported unless we're on GLES2, in which case we need an extension. // If it wasn't explicitly enabled in the configuration, we treat it like it's not supported. this.SrgbEncodingEnabled = glGraphicsConfiguration.SrgbBuffersEnabled && gl.IsHardwareSrgbSupportAvailable; // There seems to be a bug in the version of Mesa which is distributed // with Ubuntu 16.04 that causes long stalls when using glMapBufferRange. // Testing indicates that this is fixed in 11.2.2. if (glGraphicsConfiguration.UseBufferMapping) { var version = gl.GetString(gl.GL_VERSION); var versionMatchMesa = Regex.Match(version, "Mesa (?<major>\\d+).(?<minor>\\d+).(?<build>\\d+)"); if (versionMatchMesa != null && versionMatchMesa.Success) { var mesaMajor = Int32.Parse(versionMatchMesa.Groups["major"].Value); var mesaMinor = Int32.Parse(versionMatchMesa.Groups["minor"].Value); var mesaBuild = Int32.Parse(versionMatchMesa.Groups["build"].Value); var mesaVersion = new Version(mesaMajor, mesaMinor, mesaBuild); if (mesaVersion < new Version(11, 2, 2)) { glGraphicsConfiguration.UseBufferMapping = false; } } } // If we've been explicitly told to disable buffer mapping, override the caps from the driver. if (!gl.IsMapBufferRangeAvailable || !glGraphicsConfiguration.UseBufferMapping) { this.MinMapBufferAlignment = Int32.MinValue; } }
/// <summary> /// Initializes the context's primary window. /// </summary> private void InitializePrimaryWindow(UltravioletConfiguration uvconfig, SDL2PlatformConfiguration sdlconfig) { // Initialize the rendering API. if (sdlconfig.RenderingAPI != SDL2PlatformRenderingAPI.OpenGL) { throw new NotSupportedException(); } InitializeRenderingAPI(sdlconfig); renderingAPI = sdlconfig.RenderingAPI; // Retrieve the caption for our window. var caption = Localization.Strings.Contains("WINDOW_CAPTION") ? Localization.Get("WINDOW_CAPTION") : UltravioletStrings.DefaultWindowCaption.Value; // If we're running on Android or iOS, we can't create a headless context. var isRunningOnMobile = (Ultraviolet.Platform == UltravioletPlatform.Android || Ultraviolet.Platform == UltravioletPlatform.iOS); if (isRunningOnMobile && uvconfig.Headless) { throw new InvalidOperationException(SDL2Strings.CannotCreateHeadlessContextOnMobile); } // Initialize the hidden master window used to create the OpenGL context. var masterWidth = 0; var masterHeight = 0; var masterFlags = (renderingAPI == SDL2PlatformRenderingAPI.OpenGL) ? SDL_WINDOW_OPENGL : 0; if (Ultraviolet.Properties.SupportsHighDensityDisplayModes) { masterFlags |= SDL_WINDOW_ALLOW_HIGHDPI; } if (isRunningOnMobile) { masterFlags |= SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE; } else { masterFlags |= SDL_WINDOW_HIDDEN; } // Attempt to create the master window. If that fails, reduce our requirements and try again before failing. var masterptr = SDL_CreateWindow(isRunningOnMobile ? caption : String.Empty, 0, 0, masterWidth, masterHeight, masterFlags); if (masterptr == IntPtr.Zero) { var fallbackAttempt = 0; while (InitializeRenderingAPIFallback(sdlconfig, fallbackAttempt++)) { masterptr = SDL_CreateWindow(isRunningOnMobile ? caption : String.Empty, 0, 0, masterWidth, masterHeight, masterFlags); if (masterptr != IntPtr.Zero) { break; } } if (masterptr == IntPtr.Zero) { throw new SDL2Exception(); } // Fallback might have disabled sRGB, so update our configuration to reflect our current state. var srgbFramebufferEnabled = 0; unsafe { if (SDL_GL_GetAttribute(SDL_GLattr.SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, &srgbFramebufferEnabled) < 0) { throw new SDL2Exception(); } } uvconfig.SrgbBuffersEnabled = (srgbFramebufferEnabled > 0); } this.master = new SDL2UltravioletWindow(Ultraviolet, masterptr); // Set SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT so that enlisted windows // will be OpenGL-enabled and set to the correct pixel format. if (!SDL_SetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, masterptr.ToStringHex())) { throw new SDL2Exception(); } // If this is not a headless context, create the primary application window. if (!uvconfig.Headless) { if (isRunningOnMobile) { this.windows.Add(this.master); DesignatePrimary(this.master); } else { var flags = uvconfig.WindowIsVisible ? WindowFlags.None : WindowFlags.Hidden; if (uvconfig.WindowIsResizable) { flags |= WindowFlags.Resizable; } if (uvconfig.WindowIsBorderless) { flags |= WindowFlags.Borderless; } var primary = Create(caption, uvconfig.InitialWindowPosition.X, uvconfig.InitialWindowPosition.Y, uvconfig.InitialWindowPosition.Width, uvconfig.InitialWindowPosition.Height, flags); DesignatePrimary(primary); } } }
/// <summary> /// Initializes a new instance of the <see cref="UltravioletUI"/> class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> public UltravioletUI(UltravioletContext uv, UltravioletConfiguration configuration) : base(uv) { screenStacks = new UIScreenStackCollection(uv); }
/// <summary> /// Initializes a new instance of the FMODUltravioletAudio class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet configuration.</param> public FMODUltravioletAudio(UltravioletContext uv, UltravioletConfiguration configuration) : base(uv) { platformSpecificImpl = FMODPlatformSpecificImplementationDetails.Create(); platformSpecificImpl.OnInitialized(); InitializeLogging(configuration); FMOD_RESULT result; fixed(FMOD_SYSTEM **psystem = &system) { result = FMOD_System_Create(psystem); if (result != FMOD_OK) { throw new FMODException(result); } } var version = 0u; result = FMOD_System_GetVersion(system, &version); if (result != FMOD_OK) { throw new FMODException(result); } if (version < FMOD_VERSION) { throw new Exception(FMODStrings.FMODVersionMismatch.Format(FMOD_VERSION, version)); } var extradriverdata = default(void *); result = FMOD_System_Init(system, 256, FMOD_INIT_NORMAL, extradriverdata); if (result != FMOD_OK) { throw new FMODException(result); fixed(FMOD_CHANNELGROUP **pcgroupSongs = &cgroupSongs) { result = FMOD_System_CreateChannelGroup(system, "Songs", pcgroupSongs); if (result != FMOD_OK) { throw new FMODException(result); } } fixed(FMOD_CHANNELGROUP **pcgroupSoundEffects = &cgroupSoundEffects) { result = FMOD_System_CreateChannelGroup(system, "Sound Effects", pcgroupSoundEffects); if (result != FMOD_OK) { throw new FMODException(result); } } UpdateFileSource(); UpdateAudioDevices(); PlaybackDevice = GetDefaultDevice(); uv.Messages.Subscribe(this, UltravioletMessages.ApplicationCreated); uv.Messages.Subscribe(this, UltravioletMessages.ApplicationTerminating); uv.Messages.Subscribe(this, UltravioletMessages.ApplicationSuspending); uv.Messages.Subscribe(this, UltravioletMessages.ApplicationResumed); uv.Messages.Subscribe(this, UltravioletMessages.FileSourceChanged); } /// <inheritdoc/> void IMessageSubscriber <UltravioletMessageID> .ReceiveMessage(UltravioletMessageID type, MessageData data) { if (type == UltravioletMessages.ApplicationCreated) { platformSpecificImpl.OnApplicationCreated(); return; } if (type == UltravioletMessages.ApplicationTerminating) { platformSpecificImpl.OnApplicationTerminating(); return; } if (type == UltravioletMessages.ApplicationSuspending) { if (!suspended) { awaitingResume = true; Suspend(); } return; } if (type == UltravioletMessages.ApplicationResumed) { if (awaitingResume) { awaitingResume = false; Resume(); } return; } if (type == UltravioletMessages.FileSourceChanged) { UpdateFileSource(); return; } }
/// <summary> /// Initializes debug output for this context. /// </summary> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> private void InitializeDebugOutput(UltravioletConfiguration configuration) { if (!gl.IsExtensionSupported("GL_ARB_debug_output")) { Debug.WriteLine(OpenGLStrings.DebugOutputNotSupported); return; } debugCallback = configuration.DebugCallback; debugCallbackOpenGL = (source, type, id, severity, length, message, userParam) => { var messageString = Marshal.PtrToStringAnsi(message, length); var messageLevel = DebugLevels.Info; switch (severity) { case gl.DEBUG_SEVERITY_MEDIUM: messageLevel = DebugLevels.Warning; break; case gl.DEBUG_SEVERITY_HIGH: messageLevel = DebugLevels.Error; break; } debugCallback(Ultraviolet, messageLevel, messageString); }; gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.GL_DONT_CARE, 0, IntPtr.Zero, false); if ((configuration.DebugLevels & DebugLevels.Info) == DebugLevels.Info) { gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_LOW, 0, IntPtr.Zero, true); gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_NOTIFICATION, 0, IntPtr.Zero, true); } if ((configuration.DebugLevels & DebugLevels.Warning) == DebugLevels.Warning) gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_MEDIUM, 0, IntPtr.Zero, true); if ((configuration.DebugLevels & DebugLevels.Error) == DebugLevels.Error) gl.DebugMessageControl(gl.GL_DONT_CARE, gl.GL_DONT_CARE, gl.DEBUG_SEVERITY_HIGH, 0, IntPtr.Zero, true); gl.DebugMessageCallback(debugCallbackOpenGL, IntPtr.Zero); }
/// <inheritdoc/> public override void Register(UltravioletConfiguration configuration) => PresentationFoundation.Configure(configuration, presentationConfig);
/// <summary> /// Initializes the context's UI subsystem. /// </summary> /// <param name="configuration">The Ultraviolet Framework configuration settings for this context.</param> /// <returns>The UI subsystem.</returns> private IUltravioletUI InitializeUISubsystem(UltravioletConfiguration configuration) { return(new UltravioletUI(this, configuration)); }
private static void AddDebugConfig(UltravioletConfiguration configuration) { configuration.Debug = true; configuration.DebugLevels = DebugLevels.Error | DebugLevels.Warning; configuration.DebugCallback = (uv, level, message) => { System.Diagnostics.Debug.WriteLine(message); }; }
/// <summary> /// Initializes a new instance of the <see cref="SDL2UltravioletWindowInfoOpenGL"/> class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="uvconfig">The Ultraviolet configuration settings for the current context.</param> /// <param name="winconfig">The window configuration settings for the current context.</param> public SDL2UltravioletWindowInfoOpenGL(UltravioletContext uv, UltravioletConfiguration uvconfig, SDL2PlatformConfiguration winconfig) : base(uv, uvconfig, winconfig) { }
/// <summary> /// Initializes a new instance of the OpenGLUltravioletGraphics class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> public unsafe OpenGLUltravioletGraphics(UltravioletContext uv, UltravioletConfiguration configuration) : base(uv) { var glGraphicsConfiguration = configuration.GraphicsConfiguration as OpenGLGraphicsConfiguration; if (glGraphicsConfiguration == null) { throw new InvalidOperationException(OpenGLStrings.InvalidGraphicsConfiguration); } this.OpenGLEnvironment = uv.GetFactoryMethod <OpenGLEnvironmentFactory>()(uv); InitOpenGLVersion(glGraphicsConfiguration, out var versionRequested, out var versionRequired, out var isGLES); InitOpenGLEnvironment(glGraphicsConfiguration, isGLES); uv.GetPlatform().InitializePrimaryWindow(configuration); if (this.context == IntPtr.Zero && configuration.Debug) { this.context = TryCreateOpenGLContext(uv, OpenGLEnvironment, versionRequested, versionRequired, true, false) ?? IntPtr.Zero; } if (this.context == IntPtr.Zero) { this.context = TryCreateOpenGLContext(uv, OpenGLEnvironment, versionRequested, versionRequired, false, true) ?? IntPtr.Zero; } if (!OpenGLEnvironment.SetSwapInterval(1) && uv.Platform != UltravioletPlatform.iOS) { OpenGLEnvironment.ThrowPlatformErrorException(); } if (gl.Initialized) { gl.Uninitialize(); } gl.Initialize(new OpenGLInitializer(OpenGLEnvironment)); if (!gl.IsVersionAtLeast(versionRequested ?? versionRequired)) { throw new InvalidOperationException(OpenGLStrings.DoesNotMeetMinimumVersionRequirement.Format(gl.MajorVersion, gl.MinorVersion, versionRequested.Major, versionRequested.Minor)); } OpenGLState.ResetCache(); if (!VerifyCapabilities()) { throw new NotSupportedException(OpenGLStrings.UnsupportedGraphicsDevice); } if (configuration.Debug && configuration.DebugCallback != null) { InitializeDebugOutput(configuration); } this.Capabilities = new OpenGLGraphicsCapabilities(configuration); if (Capabilities.SrgbEncodingEnabled && gl.IsFramebufferSrgbAvailable) { gl.Enable(gl.GL_FRAMEBUFFER_SRGB); gl.ThrowIfError(); } this.maxTextureStages = gl.GetInteger(gl.GL_MAX_TEXTURE_IMAGE_UNITS); this.textures = new Texture[maxTextureStages]; this.samplerStates = new SamplerState[maxTextureStages]; this.samplerObjects = Capabilities.SupportsIndependentSamplerState ? new OpenGLSamplerObject[maxTextureStages] : null; this.backBufferRenderTargetUsage = glGraphicsConfiguration.BackBufferRenderTargetUsage; if (samplerObjects != null) { for (int i = 0; i < samplerObjects.Length; i++) { samplerObjects[i] = new OpenGLSamplerObject(Ultraviolet); samplerObjects[i].Bind((uint)i); } } OpenGLState.VerifyCache(); ResetDeviceStates(); }