diff --git a/OpenRA.Game/Settings.cs b/OpenRA.Game/Settings.cs index 3bcfd83e91..b595b5c90c 100644 --- a/OpenRA.Game/Settings.cs +++ b/OpenRA.Game/Settings.cs @@ -160,6 +160,9 @@ namespace OpenRA [Desc("Disable separate OpenGL render thread on Windows operating systems.")] public bool DisableWindowsRenderThread = true; + [Desc("Use OpenGL ES if both ES and regular OpenGL are available.")] + public bool PreferGLES = false; + public int BatchSize = 8192; public int SheetSize = 2048; diff --git a/OpenRA.Platforms.Default/FrameBuffer.cs b/OpenRA.Platforms.Default/FrameBuffer.cs index 002b7b5c09..4388701953 100644 --- a/OpenRA.Platforms.Default/FrameBuffer.cs +++ b/OpenRA.Platforms.Default/FrameBuffer.cs @@ -33,31 +33,32 @@ namespace OpenRA.Platforms.Default OpenGL.glGenFramebuffers(1, out framebuffer); OpenGL.CheckGLError(); - OpenGL.glBindFramebuffer(OpenGL.FRAMEBUFFER_EXT, framebuffer); + OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, framebuffer); OpenGL.CheckGLError(); // Color this.texture = texture; texture.SetEmpty(size.Width, size.Height); - OpenGL.glFramebufferTexture2D(OpenGL.FRAMEBUFFER_EXT, OpenGL.COLOR_ATTACHMENT0_EXT, OpenGL.GL_TEXTURE_2D, texture.ID, 0); + OpenGL.glFramebufferTexture2D(OpenGL.GL_FRAMEBUFFER, OpenGL.GL_COLOR_ATTACHMENT0, OpenGL.GL_TEXTURE_2D, texture.ID, 0); OpenGL.CheckGLError(); // Depth OpenGL.glGenRenderbuffers(1, out depth); OpenGL.CheckGLError(); - OpenGL.glBindRenderbuffer(OpenGL.RENDERBUFFER_EXT, depth); + OpenGL.glBindRenderbuffer(OpenGL.GL_RENDERBUFFER, depth); OpenGL.CheckGLError(); - OpenGL.glRenderbufferStorage(OpenGL.RENDERBUFFER_EXT, OpenGL.GL_DEPTH_COMPONENT, size.Width, size.Height); + var glDepth = OpenGL.Features.HasFlag(OpenGL.GLFeatures.GLES) ? OpenGL.GL_DEPTH_COMPONENT16 : OpenGL.GL_DEPTH_COMPONENT; + OpenGL.glRenderbufferStorage(OpenGL.GL_RENDERBUFFER, glDepth, size.Width, size.Height); OpenGL.CheckGLError(); - OpenGL.glFramebufferRenderbuffer(OpenGL.FRAMEBUFFER_EXT, OpenGL.DEPTH_ATTACHMENT_EXT, OpenGL.RENDERBUFFER_EXT, depth); + OpenGL.glFramebufferRenderbuffer(OpenGL.GL_FRAMEBUFFER, OpenGL.GL_DEPTH_ATTACHMENT, OpenGL.GL_RENDERBUFFER, depth); OpenGL.CheckGLError(); // Test for completeness - var status = OpenGL.glCheckFramebufferStatus(OpenGL.FRAMEBUFFER_EXT); - if (status != OpenGL.FRAMEBUFFER_COMPLETE_EXT) + var status = OpenGL.glCheckFramebufferStatus(OpenGL.GL_FRAMEBUFFER); + if (status != OpenGL.GL_FRAMEBUFFER_COMPLETE) { var error = "Error creating framebuffer: {0}\n{1}".F(status, new StackTrace()); OpenGL.WriteGraphicsLog(error); @@ -65,19 +66,14 @@ namespace OpenRA.Platforms.Default } // Restore default buffer - OpenGL.glBindFramebuffer(OpenGL.FRAMEBUFFER_EXT, 0); + OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, 0); OpenGL.CheckGLError(); } static int[] ViewportRectangle() { var v = new int[4]; - unsafe - { - fixed (int* ptr = &v[0]) - OpenGL.glGetIntegerv(OpenGL.GL_VIEWPORT, ptr); - } - + OpenGL.glGetIntegerv(OpenGL.GL_VIEWPORT, out v[0]); OpenGL.CheckGLError(); return v; } @@ -92,7 +88,7 @@ namespace OpenRA.Platforms.Default OpenGL.glFlush(); OpenGL.CheckGLError(); - OpenGL.glBindFramebuffer(OpenGL.FRAMEBUFFER_EXT, framebuffer); + OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, framebuffer); OpenGL.CheckGLError(); OpenGL.glViewport(0, 0, size.Width, size.Height); OpenGL.CheckGLError(); @@ -107,7 +103,7 @@ namespace OpenRA.Platforms.Default VerifyThreadAffinity(); OpenGL.glFlush(); OpenGL.CheckGLError(); - OpenGL.glBindFramebuffer(OpenGL.FRAMEBUFFER_EXT, 0); + OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, 0); OpenGL.CheckGLError(); OpenGL.glViewport(cv[0], cv[1], cv[2], cv[3]); OpenGL.CheckGLError(); diff --git a/OpenRA.Platforms.Default/OpenGL.cs b/OpenRA.Platforms.Default/OpenGL.cs index 58ff9ec72a..d74f05b2cc 100644 --- a/OpenRA.Platforms.Default/OpenGL.cs +++ b/OpenRA.Platforms.Default/OpenGL.cs @@ -24,11 +24,12 @@ namespace OpenRA.Platforms.Default Justification = "C-style naming is kept for consistency with the underlying native API.")] internal static class OpenGL { + [Flags] public enum GLFeatures { None = 0, - GL2OrGreater = 1, - FramebufferExt = 4, + Core = 1, + GLES = 2, } public static GLFeatures Features { get; private set; } @@ -105,6 +106,7 @@ namespace OpenRA.Platforms.Default public const int GL_DYNAMIC_DRAW = 0x88E8; public const int GL_TEXTURE0 = 0x84C0; + public const int GL_DEPTH_COMPONENT16 = 0x81A5; // OpenGL 2 public const int GL_FRAGMENT_SHADER = 0x8B30; @@ -127,14 +129,17 @@ namespace OpenRA.Platforms.Default public const int GL_RENDERER = 0x1F01; public const int GL_VERSION = 0x1F02; public const int GL_EXTENSIONS = 0x1F03; + public const int GL_NUM_EXTENSIONS = 0x821D; + public const int GL_SHADING_LANGUAGE_VERSION = 0x8B8C; // Framebuffers - public const int FRAMEBUFFER_EXT = 0x8D40; - public const int RENDERBUFFER_EXT = 0x8D41; - public const int COLOR_ATTACHMENT0_EXT = 0x8CE0; - public const int DEPTH_ATTACHMENT_EXT = 0x8D00; - public const int FRAMEBUFFER_COMPLETE_EXT = 0x8CD5; + public const int GL_FRAMEBUFFER = 0x8D40; + public const int GL_RENDERBUFFER = 0x8D41; + public const int GL_COLOR_ATTACHMENT0 = 0x8CE0; + public const int GL_DEPTH_ATTACHMENT = 0x8D00; + public const int GL_FRAMEBUFFER_COMPLETE = 0x8CD5; + public const int GL_FRAMEBUFFER_BINDING = 0x8CA6; public delegate void Flush(); public static Flush glFlush { get; private set; } @@ -162,7 +167,18 @@ namespace OpenRA.Platforms.Default } } - public unsafe delegate int GetIntegerv(int pname, int* param); + delegate IntPtr GetStringi(int name, uint index); + static GetStringi glGetStringiInternal; + + public static string glGetStringi(int name, uint index) + { + unsafe + { + return new string((sbyte*)glGetStringiInternal(name, index)); + } + } + + public unsafe delegate int GetIntegerv(int pname, out int param); public static GetIntegerv glGetIntegerv { get; private set; } public delegate void Finish(); @@ -241,6 +257,12 @@ namespace OpenRA.Platforms.Default public delegate void BindBuffer(int target, uint buffer); public static BindBuffer glBindBuffer { get; private set; } + public delegate void GenVertexArrays(int n, out uint buffers); + public static GenVertexArrays glGenVertexArrays { get; private set; } + + public delegate void BindVertexArray(uint buffer); + public static BindVertexArray glBindVertexArray { get; private set; } + public delegate void BufferData(int target, IntPtr size, IntPtr data, int usage); public static BufferData glBufferData { get; private set; } @@ -253,6 +275,9 @@ namespace OpenRA.Platforms.Default public delegate void BindAttribLocation(uint program, int index, string name); public static BindAttribLocation glBindAttribLocation { get; private set; } + public delegate void BindFragDataLocation(uint program, int colorNumber, string name); + public static BindFragDataLocation glBindFragDataLocation { get; private set; } + public delegate void VertexAttribPointer(int index, int size, int type, bool normalized, int stride, IntPtr pointer); public static VertexAttribPointer glVertexAttribPointer { get; private set; } @@ -361,6 +386,7 @@ namespace OpenRA.Platforms.Default { glGetError = Bind("glGetError"); glGetStringInternal = Bind("glGetString"); + glGetStringiInternal = Bind("glGetStringi"); } catch (Exception) { @@ -368,7 +394,7 @@ namespace OpenRA.Platforms.Default } DetectGLFeatures(); - if (!Features.HasFlag(GLFeatures.GL2OrGreater) || !Features.HasFlag(GLFeatures.FramebufferExt)) + if (!Features.HasFlag(GLFeatures.Core)) { WriteGraphicsLog("Unsupported OpenGL version: " + glGetString(GL_VERSION)); throw new InvalidProgramException("OpenGL Version Error: See graphics.log for details."); @@ -411,7 +437,10 @@ namespace OpenRA.Platforms.Default glBufferData = Bind("glBufferData"); glBufferSubData = Bind("glBufferSubData"); glDeleteBuffers = Bind("glDeleteBuffers"); + glGenVertexArrays = Bind("glGenVertexArrays"); + glBindVertexArray = Bind("glBindVertexArray"); glBindAttribLocation = Bind("glBindAttribLocation"); + glBindFragDataLocation = Bind("glBindFragDataLocation"); glVertexAttribPointer = Bind("glVertexAttribPointer"); glEnableVertexAttribArray = Bind("glEnableVertexAttribArray"); glDisableVertexAttribArray = Bind("glDisableVertexAttribArray"); @@ -433,16 +462,16 @@ namespace OpenRA.Platforms.Default glGetTexImage = Bind("glGetTexImage"); glTexParameteri = Bind("glTexParameteri"); glTexParameterf = Bind("glTexParameterf"); - glGenFramebuffers = Bind("glGenFramebuffersEXT"); - glBindFramebuffer = Bind("glBindFramebufferEXT"); - glFramebufferTexture2D = Bind("glFramebufferTexture2DEXT"); - glDeleteFramebuffers = Bind("glDeleteFramebuffersEXT"); - glGenRenderbuffers = Bind("glGenRenderbuffersEXT"); - glBindRenderbuffer = Bind("glBindRenderbufferEXT"); - glRenderbufferStorage = Bind("glRenderbufferStorageEXT"); - glDeleteRenderbuffers = Bind("glDeleteRenderbuffersEXT"); - glFramebufferRenderbuffer = Bind("glFramebufferRenderbufferEXT"); - glCheckFramebufferStatus = Bind("glCheckFramebufferStatusEXT"); + glGenFramebuffers = Bind("glGenFramebuffers"); + glBindFramebuffer = Bind("glBindFramebuffer"); + glFramebufferTexture2D = Bind("glFramebufferTexture2D"); + glDeleteFramebuffers = Bind("glDeleteFramebuffers"); + glGenRenderbuffers = Bind("glGenRenderbuffers"); + glBindRenderbuffer = Bind("glBindRenderbuffer"); + glRenderbufferStorage = Bind("glRenderbufferStorage"); + glDeleteRenderbuffers = Bind("glDeleteRenderbuffers"); + glFramebufferRenderbuffer = Bind("glFramebufferRenderbuffer"); + glCheckFramebufferStatus = Bind("glCheckFramebufferStatus"); } catch (Exception e) { @@ -461,22 +490,24 @@ namespace OpenRA.Platforms.Default try { Version = glGetString(GL_VERSION); - var version = Version.Contains(" ") ? Version.Split(' ')[0].Split('.') : Version.Split('.'); var major = 0; - if (version.Length > 0) - int.TryParse(version[0], out major); - var minor = 0; - if (version.Length > 1) - int.TryParse(version[1], out minor); - if (major >= 2 && minor >= 0) - Features |= GLFeatures.GL2OrGreater; + // Assume that the first numeric token corresponds to the GL version + foreach (var t in Version.Split()) + { + var split = t.Split('.'); + if (split.Length >= 2 && int.TryParse(split[0], out major) && int.TryParse(split[1], out minor)) + break; + } - var hasFramebufferExt = SDL.SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object") == SDL.SDL_bool.SDL_TRUE; - if (hasFramebufferExt) - Features |= GLFeatures.FramebufferExt; + // Core features are defined as the shared feature set of GL 3.2 and (GLES 3 + BGRA extension) + var hasBGRA = SDL.SDL_GL_ExtensionSupported("GL_EXT_texture_format_BGRA8888") == SDL.SDL_bool.SDL_TRUE; + if (Version.Contains(" ES") && hasBGRA && major >= 3) + Features = GLFeatures.Core | GLFeatures.GLES; + else if (major > 3 || (major == 3 && minor >= 2)) + Features = GLFeatures.Core; } catch (Exception) { } } @@ -516,7 +547,11 @@ namespace OpenRA.Platforms.Default Log.Write("graphics", "GL Version: {0}", glGetString(GL_VERSION)); Log.Write("graphics", "Shader Version: {0}", glGetString(GL_SHADING_LANGUAGE_VERSION)); Log.Write("graphics", "Available extensions:"); - Log.Write("graphics", glGetString(GL_EXTENSIONS)); + + int extensionCount; + glGetIntegerv(GL_NUM_EXTENSIONS, out extensionCount); + for (var i = 0; i < extensionCount; i++) + Log.Write("graphics", glGetStringi(GL_EXTENSIONS, (uint)i)); } } } diff --git a/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs b/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs index 5c62bcca96..3779ca84e7 100644 --- a/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs +++ b/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs @@ -37,6 +37,13 @@ namespace OpenRA.Platforms.Default OpenGL.Initialize(); + uint vao; + OpenGL.CheckGLError(); + OpenGL.glGenVertexArrays(1, out vao); + OpenGL.CheckGLError(); + OpenGL.glBindVertexArray(vao); + OpenGL.CheckGLError(); + OpenGL.glEnableVertexAttribArray(Shader.VertexPosAttributeIndex); OpenGL.CheckGLError(); OpenGL.glEnableVertexAttribArray(Shader.TexCoordAttributeIndex); diff --git a/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs b/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs index 820e1f6a64..265e6bb56c 100644 --- a/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs +++ b/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs @@ -75,8 +75,6 @@ namespace OpenRA.Platforms.Default public Sdl2PlatformWindow(Size requestWindowSize, WindowMode windowMode, int batchSize) { - Console.WriteLine("Using SDL 2 with OpenGL renderer"); - // Lock the Window/Surface properties until initialization is complete lock (syncObject) { @@ -93,6 +91,25 @@ namespace OpenRA.Platforms.Default SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0); + // Decide between OpenGL and OpenGL ES rendering + // Test whether we can use the preferred renderer and fall back to the other if that fails + // If neither works we will throw a graphics error later when trying to create the real window + bool useGLES; + if (Game.Settings.Graphics.PreferGLES) + useGLES = CanCreateGLWindow(3, 0, SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_ES); + else + useGLES = !CanCreateGLWindow(3, 2, SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE); + + var glMajor = 3; + var glMinor = useGLES ? 0 : 2; + var glProfile = useGLES ? SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_ES : SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE; + + SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, glMajor); + SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, glMinor); + SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, (int)glProfile); + + Console.WriteLine("Using SDL 2 with OpenGL{0} renderer", useGLES ? " ES" : ""); + SDL.SDL_DisplayMode display; SDL.SDL_GetCurrentDisplayMode(0, out display); @@ -366,5 +383,33 @@ namespace OpenRA.Platforms.Default VerifyThreadAffinity(); return input.SetClipboardText(text); } + + static bool CanCreateGLWindow(int major, int minor, SDL.SDL_GLprofile profile) + { + // Implementation inspired by TestIndividualGLVersion from Veldrid + SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, major); + SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, minor); + SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, (int)profile); + + var flags = SDL.SDL_WindowFlags.SDL_WINDOW_HIDDEN | SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL; + var window = SDL.SDL_CreateWindow("", 0, 0, 1, 1, flags); + if (window == IntPtr.Zero || !string.IsNullOrEmpty(SDL.SDL_GetError())) + { + SDL.SDL_ClearError(); + return false; + } + + var context = SDL.SDL_GL_CreateContext(window); + if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window, context) < 0) + { + SDL.SDL_ClearError(); + SDL.SDL_DestroyWindow(window); + return false; + } + + SDL.SDL_GL_DeleteContext(context); + SDL.SDL_DestroyWindow(window); + return true; + } } } diff --git a/OpenRA.Platforms.Default/Shader.cs b/OpenRA.Platforms.Default/Shader.cs index 43d3c9e592..5ea33c9e56 100644 --- a/OpenRA.Platforms.Default/Shader.cs +++ b/OpenRA.Platforms.Default/Shader.cs @@ -33,6 +33,9 @@ namespace OpenRA.Platforms.Default var filename = Path.Combine(Platform.GameDir, "glsl", name + "." + ext); var code = File.ReadAllText(filename); + var version = OpenGL.Features.HasFlag(OpenGL.GLFeatures.GLES) ? "300 es" : "140"; + code = code.Replace("{VERSION}", version); + var shader = OpenGL.glCreateShader(type); OpenGL.CheckGLError(); unsafe @@ -77,6 +80,9 @@ namespace OpenRA.Platforms.Default OpenGL.CheckGLError(); OpenGL.glBindAttribLocation(program, TexMetadataAttributeIndex, "aVertexTexMetadata"); OpenGL.CheckGLError(); + OpenGL.glBindFragDataLocation(program, 0, "fragColor"); + OpenGL.CheckGLError(); + OpenGL.glAttachShader(program, vertexShader); OpenGL.CheckGLError(); OpenGL.glAttachShader(program, fragmentShader); @@ -135,6 +141,7 @@ namespace OpenRA.Platforms.Default { VerifyThreadAffinity(); OpenGL.glUseProgram(program); + OpenGL.CheckGLError(); // bind the textures foreach (var kv in textures) diff --git a/OpenRA.Platforms.Default/Texture.cs b/OpenRA.Platforms.Default/Texture.cs index c76bf59aec..995e535994 100644 --- a/OpenRA.Platforms.Default/Texture.cs +++ b/OpenRA.Platforms.Default/Texture.cs @@ -85,7 +85,8 @@ namespace OpenRA.Platforms.Default { var intPtr = new IntPtr((void*)ptr); PrepareTexture(); - OpenGL.glTexImage2D(OpenGL.GL_TEXTURE_2D, 0, OpenGL.GL_RGBA8, width, height, + var glInternalFormat = OpenGL.Features.HasFlag(OpenGL.GLFeatures.GLES) ? OpenGL.GL_BGRA : OpenGL.GL_RGBA8; + OpenGL.glTexImage2D(OpenGL.GL_TEXTURE_2D, 0, glInternalFormat, width, height, 0, OpenGL.GL_BGRA, OpenGL.GL_UNSIGNED_BYTE, intPtr); OpenGL.CheckGLError(); } @@ -109,7 +110,8 @@ namespace OpenRA.Platforms.Default { var intPtr = new IntPtr((void*)ptr); PrepareTexture(); - OpenGL.glTexImage2D(OpenGL.GL_TEXTURE_2D, 0, OpenGL.GL_RGBA8, width, height, + var glInternalFormat = OpenGL.Features.HasFlag(OpenGL.GLFeatures.GLES) ? OpenGL.GL_BGRA : OpenGL.GL_RGBA8; + OpenGL.glTexImage2D(OpenGL.GL_TEXTURE_2D, 0, glInternalFormat, width, height, 0, OpenGL.GL_BGRA, OpenGL.GL_UNSIGNED_BYTE, intPtr); OpenGL.CheckGLError(); } @@ -121,19 +123,51 @@ namespace OpenRA.Platforms.Default VerifyThreadAffinity(); var data = new byte[4 * Size.Width * Size.Height]; - OpenGL.CheckGLError(); - OpenGL.glBindTexture(OpenGL.GL_TEXTURE_2D, texture); - unsafe + // GLES doesn't support glGetTexImage so data must be read back via a frame buffer + if (OpenGL.Features.HasFlag(OpenGL.GLFeatures.GLES)) { - fixed (byte* ptr = &data[0]) + // Query the active framebuffer so we can restore it afterwards + int lastFramebuffer; + OpenGL.glGetIntegerv(OpenGL.GL_FRAMEBUFFER_BINDING, out lastFramebuffer); + + uint framebuffer; + OpenGL.glGenFramebuffers(1, out framebuffer); + OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, framebuffer); + OpenGL.CheckGLError(); + + OpenGL.glFramebufferTexture2D(OpenGL.GL_FRAMEBUFFER, OpenGL.GL_COLOR_ATTACHMENT0, OpenGL.GL_TEXTURE_2D, texture, 0); + OpenGL.CheckGLError(); + + unsafe { - var intPtr = new IntPtr((void*)ptr); - OpenGL.glGetTexImage(OpenGL.GL_TEXTURE_2D, 0, OpenGL.GL_BGRA, - OpenGL.GL_UNSIGNED_BYTE, intPtr); + fixed (byte* ptr = &data[0]) + { + var intPtr = new IntPtr((void*)ptr); + OpenGL.glReadPixels(0, 0, Size.Width, Size.Height, OpenGL.GL_BGRA, OpenGL.GL_UNSIGNED_BYTE, intPtr); + OpenGL.CheckGLError(); + } } + + OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, (uint)lastFramebuffer); + OpenGL.glDeleteFramebuffers(1, ref framebuffer); + OpenGL.CheckGLError(); + } + else + { + OpenGL.glBindTexture(OpenGL.GL_TEXTURE_2D, texture); + unsafe + { + fixed (byte* ptr = &data[0]) + { + var intPtr = new IntPtr((void*)ptr); + OpenGL.glGetTexImage(OpenGL.GL_TEXTURE_2D, 0, OpenGL.GL_BGRA, + OpenGL.GL_UNSIGNED_BYTE, intPtr); + } + } + + OpenGL.CheckGLError(); } - OpenGL.CheckGLError(); return data; } @@ -145,7 +179,8 @@ namespace OpenRA.Platforms.Default Size = new Size(width, height); PrepareTexture(); - OpenGL.glTexImage2D(OpenGL.GL_TEXTURE_2D, 0, OpenGL.GL_RGBA8, width, height, + var glInternalFormat = OpenGL.Features.HasFlag(OpenGL.GLFeatures.GLES) ? OpenGL.GL_BGRA : OpenGL.GL_RGBA8; + OpenGL.glTexImage2D(OpenGL.GL_TEXTURE_2D, 0, glInternalFormat, width, height, 0, OpenGL.GL_BGRA, OpenGL.GL_UNSIGNED_BYTE, IntPtr.Zero); OpenGL.CheckGLError(); } diff --git a/glsl/combined.frag b/glsl/combined.frag index 441e1868dd..109e776bc7 100644 --- a/glsl/combined.frag +++ b/glsl/combined.frag @@ -1,3 +1,10 @@ +#version {VERSION} +#ifdef GL_ES +precision mediump float; +#endif + +in vec4 vColor; + uniform sampler2D Texture0; uniform sampler2D Texture1; uniform sampler2D Texture2; @@ -10,15 +17,17 @@ uniform sampler2D Palette; uniform bool EnableDepthPreview; uniform float DepthTextureScale; -varying vec4 vTexCoord; -varying vec2 vTexMetadata; -varying vec4 vChannelMask; -varying vec4 vDepthMask; -varying vec2 vTexSampler; +in vec4 vTexCoord; +in vec2 vTexMetadata; +in vec4 vChannelMask; +in vec4 vDepthMask; +in vec2 vTexSampler; -varying vec4 vColorFraction; -varying vec4 vRGBAFraction; -varying vec4 vPalettedFraction; +in vec4 vColorFraction; +in vec4 vRGBAFraction; +in vec4 vPalettedFraction; + +out vec4 fragColor; float jet_r(float x) { @@ -38,26 +47,26 @@ float jet_b(float x) vec4 Sample(float samplerIndex, vec2 pos) { if (samplerIndex < 0.5) - return texture2D(Texture0, pos); + return texture(Texture0, pos); else if (samplerIndex < 1.5) - return texture2D(Texture1, pos); + return texture(Texture1, pos); else if (samplerIndex < 2.5) - return texture2D(Texture2, pos); + return texture(Texture2, pos); else if (samplerIndex < 3.5) - return texture2D(Texture3, pos); + return texture(Texture3, pos); else if (samplerIndex < 4.5) - return texture2D(Texture4, pos); + return texture(Texture4, pos); else if (samplerIndex < 5.5) - return texture2D(Texture5, pos); + return texture(Texture5, pos); - return texture2D(Texture6, pos); + return texture(Texture6, pos); } void main() { vec4 x = Sample(vTexSampler.s, vTexCoord.st); vec2 p = vec2(dot(x, vChannelMask), vTexMetadata.s); - vec4 c = vPalettedFraction * texture2D(Palette, p) + vRGBAFraction * x + vColorFraction * vTexCoord; + vec4 c = vPalettedFraction * texture(Palette, p) + vRGBAFraction * x + vColorFraction * vTexCoord; // Discard any transparent fragments (both color and depth) if (c.a == 0.0) @@ -79,8 +88,8 @@ void main() float r = clamp(jet_r(x), 0.0, 1.0); float g = clamp(jet_g(x), 0.0, 1.0); float b = clamp(jet_b(x), 0.0, 1.0); - gl_FragColor = vec4(r, g, b, 1.0); + fragColor = vec4(r, g, b, 1.0); } else - gl_FragColor = c; + fragColor = c; } diff --git a/glsl/combined.vert b/glsl/combined.vert index 674b7548b9..db42199e82 100644 --- a/glsl/combined.vert +++ b/glsl/combined.vert @@ -1,19 +1,21 @@ +#version {VERSION} + uniform vec3 Scroll; uniform vec3 r1, r2; -attribute vec4 aVertexPosition; -attribute vec4 aVertexTexCoord; -attribute vec2 aVertexTexMetadata; +in vec4 aVertexPosition; +in vec4 aVertexTexCoord; +in vec2 aVertexTexMetadata; -varying vec4 vTexCoord; -varying vec2 vTexMetadata; -varying vec4 vChannelMask; -varying vec4 vDepthMask; -varying vec2 vTexSampler; +out vec4 vTexCoord; +out vec2 vTexMetadata; +out vec4 vChannelMask; +out vec4 vDepthMask; +out vec2 vTexSampler; -varying vec4 vColorFraction; -varying vec4 vRGBAFraction; -varying vec4 vPalettedFraction; +out vec4 vColorFraction; +out vec4 vRGBAFraction; +out vec4 vPalettedFraction; vec4 UnpackChannelAttributes(float x) { diff --git a/glsl/model.frag b/glsl/model.frag index 70293af91b..ce3e744c27 100644 --- a/glsl/model.frag +++ b/glsl/model.frag @@ -1,22 +1,28 @@ +#version {VERSION} +#ifdef GL_ES +precision mediump float; +#endif + uniform sampler2D Palette, DiffuseTexture; uniform vec2 PaletteRows; uniform vec4 LightDirection; uniform vec3 AmbientLight, DiffuseLight; -varying vec4 vTexCoord; -varying vec4 vChannelMask; -varying vec4 vNormalsMask; +in vec4 vTexCoord; +in vec4 vChannelMask; +in vec4 vNormalsMask; +out vec4 fragColor; void main() { - vec4 x = texture2D(DiffuseTexture, vTexCoord.st); - vec4 color = texture2D(Palette, vec2(dot(x, vChannelMask), PaletteRows.x)); + vec4 x = texture(DiffuseTexture, vTexCoord.st); + vec4 color = texture(Palette, vec2(dot(x, vChannelMask), PaletteRows.x)); if (color.a < 0.01) discard; - vec4 y = texture2D(DiffuseTexture, vTexCoord.pq); - vec4 normal = (2.0 * texture2D(Palette, vec2(dot(y, vNormalsMask), PaletteRows.y)) - 1.0); + vec4 y = texture(DiffuseTexture, vTexCoord.pq); + vec4 normal = (2.0 * texture(Palette, vec2(dot(y, vNormalsMask), PaletteRows.y)) - 1.0); vec3 intensity = AmbientLight + DiffuseLight * max(dot(normal, LightDirection), 0.0); - gl_FragColor = vec4(intensity * color.rgb, color.a); + fragColor = vec4(intensity * color.rgb, color.a); } diff --git a/glsl/model.vert b/glsl/model.vert index fa268ea186..30fdb34a94 100644 --- a/glsl/model.vert +++ b/glsl/model.vert @@ -1,12 +1,14 @@ +#version {VERSION} + uniform mat4 View; uniform mat4 TransformMatrix; -attribute vec4 aVertexPosition; -attribute vec4 aVertexTexCoord; -attribute vec2 aVertexTexMetadata; -varying vec4 vTexCoord; -varying vec4 vChannelMask; -varying vec4 vNormalsMask; +in vec4 aVertexPosition; +in vec4 aVertexTexCoord; +in vec2 aVertexTexMetadata; +out vec4 vTexCoord; +out vec4 vChannelMask; +out vec4 vNormalsMask; vec4 DecodeMask(float x) {